2016-08-15 29 views
0

是否可以在剃须刀视图中使用自定义滤镜?是否可以在Razor视图中使用基于AuthorizeAttribute的自定义过滤器?

例如,我有这样的工作在一个控制器:

[Privilege(Privileges ="AdminRead, AdminWrite"))] 
public ActionResult Index() 
{ 
return View(); 
} 

但是,有没有可能做一些像剃刀CSHTML文件中的以下内容:

if(@[Privilege(Privileges ="AdminRead, AdminWrite"))]) 
{ 
//html goes here 
} 

如果它使差异,PrivilegeAttribute从AuthorizeAttribute派生。

PrivilegeAttribute.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Security.Claims; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Security; 

namespace IdentityDevelopment.Infrastructure 
{ 
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 
    public class PrivilegeAttribute : AuthorizeAttribute 
    { 
     private static readonly string[] _emptyArray = new string[0]; 


     private string _privileges; 
     private string[] _privilegesSplit = _emptyArray; 

     public string Privileges 
     { 
      get { return _privileges ?? String.Empty; } 
      set 
      { 
       _privileges = value; 
       _privilegesSplit = SplitString(value); 
      } 
     } 

     internal static string[] SplitString(string original) 
     { 
      if (String.IsNullOrEmpty(original)) 
      { 
       return _emptyArray; 
      } 

      var split = from piece in original.Split(',') 
         let trimmed = piece.Trim() 
         where !String.IsNullOrEmpty(trimmed) 
         select trimmed; 
      return split.ToArray(); 
     } 

     public PrivilegeAttribute(string privilegeList) 
    { 
     _privileges = privilegeList; 
    } 
     protected override bool AuthorizeCore(HttpContextBase httpContext) 
     { 
      bool isAuthorized = base.AuthorizeCore(httpContext); 

      if (isAuthorized) { 
       string[] rolesArray; 

       var roles = ((ClaimsIdentity)httpContext.User.Identity).Claims 
        .Where(c => c.Type == ClaimTypes.Role) 
        .Select(c => c.Value); 

       rolesArray = roles.ToArray(); 

       //Assume that a user can only be associated to 0 or 1 role. If 0 the rolesArray will be null. 

       if (rolesArray != null) 
       { 
        string roleUser = rolesArray[0]; 

        SQLRolerecord CheckPrivInRole = new SQLRolerecord(); 

        return CheckPrivInRole.Allow(roleUser, _privilegesSplit); 

       } 
       else 
       { 
        return false; 
       } 
      } 
      else 
      { 
       return false; 
      } 


     } 

    } 
} 

谢谢。

+1

这不可能吗? '@if(User.IsInRole(“WhateverUserRole”))' – techspider

+0

或'@if(User.IsAuthorized)'应该这样做 – jbutler483

+0

@techspider是的,我已经使用过它,这是可能的,但自定义AuthorizeAttributes呢?例如,我有一个名为PrivilegeAttribute的接受名为“Privileges”的输入,那么我将如何能够做出类似的事情呢?我如何创建一个名为IsInPrivilege的方法? – ITWorker

回答

1

我相信你的问题的答案封装得很好here

您可以基于角色基于安全性限制用户查看。

@if (User.IsInRole("Admin")) 
{ 
    //here blocks that you want to show to users with Admin role 
} 

您也可以处理通过控制器权限等。

public ActionResult Index() 
{ 
    if(User.IsInRole("Admin")) 
    { 
     return View("Admin"); 
    } 
    return View("User"); 
} 

但是,您特别需要Authorize等属性。

[Authorize(Roles = "Admin")] 
public ActionResult SaveTopSecret() 
{ 

} 
+0

我想你可能已经写了这个答案,而我正在编辑。我知道如何使用User.IsInRole来做到这一点,但我想知道是否可以使用自定义类型的授权来完成,而这正是我在原始问题中编辑过的内容。 – ITWorker

1

将属性或过滤器添加到视图不是首选。你可以在this MSDN article获得战利品。

这些过滤器可应用于操作方法,控制器或应用程序级别的 。

您也可以通过在您的视图中检查User.IsInRole并执行所需的操作来实现同样的效果。

另外,您还可以实现自定义HTML助手,它可以像HTML控件上的扩展方法一样工作。您可以在问题here中查看示例。

1

从理论上说,由于ViewContext延伸ControllerContext,那么你可以用属性和调用它是这样的:

@if(new PrivilegeAttribute{Privileges = "AdminRead, AdminWrite"} 
     .AuthorizeCore(new AuthorizationContext(this.ViewContext))) 
{ 
    ... 
} 

这是不一样的“添加属性”的观点,但它可以让你在您的视图中重用属性的自定义逻辑,以避免重复代码。

不过,我要指出的是,首选的方式来完成你正在做的是:

  1. 把逻辑放到一个单独的类
  2. 注入这个类(或它的接口)到您的控制器
  3. 让控制器操作调用该类/接口的方法来发现用户是否具有权限。
  4. 将控制器动作保存到强类型视图模型中,并将视图模型传递到视图中
  5. 让视图访问视图模型属性以确定如何显示内容。
+0

有趣的命题!你试过这个吗?是否可以使其等同于[[Privilege(Privileges =“AdminRead,AdminWrite”))]? – techspider

+0

@techspider:我还没有尝试过,但我想不出任何理由它不应该工作。查看我的更新答案,了解如何使其与您发布的内容相当。 – StriplingWarrior

+0

我会研究你发布的首选方法,但是当我尝试用Razor代码建议的方法时,我看到错误消息'The type or namespace name'PrivilegeAttribute could not be found(你是否缺少using指令或者是一个程序集引用?)'我的视图此时不是强类型的任何模型。 – ITWorker

1

好吧,我已经下了AuthorizeAttribute路线使用枚举设置权限。它似乎更清楚一点,并且使用字符串来定义权限的时候会少一些。

所以这工作得很好控制器

[AccessRole(AccessLevel.SuperAdmin, AccessLevel.Admin)] 

例如。现在我们必须对付剃刀。 步骤1添加到您的AccessRole类

public bool Auth(HttpContextBase httpContext) 
     { 
      return this.AuthorizeCore(httpContext); 
     } 

步骤2:添加该类这(访问级别为枚举)

public static class AccessRoleHelper { 


     public static bool IsInRole(HttpContextBase httpContext, params AccessLevel[] roles) 
    { 

     var ac = new AccessRole(roles); 

     return ac.Auth(httpContext); 

    } 



    } 

步骤3.添加命名空间到剃刀web.cong

第4步。

@if (AccessRoleHelper.IsInRole(this.Context, AccessLevel.Admin, AccessLevel.SuperAdmin)) 
    <p>has access</p> 
} 

嗯,我还在学习c# - 但我一如既往地问myse如果我对这个解决方案感到满意吗?时间会证明。但解决方案不是那么少。

[编辑] 您可以将更多包含命名空间添加到剃须刀中进行一些清理。

+0

当我读到你的答案时,我最终实现了这个版本。感谢您的回应。 – ITWorker

1

一个Attribute是...

摘录:

相关联的元数据,或声明的信息,与代码(组件,类型,方法,属性等)的有效方法。在一个属性与一个程序实体关联后,可以在运行时使用称为反射的技术来查询该属性。

所以,你的代码:

if(@[Privilege(Privileges ="AdminRead, AdminWrite"))]) 
{ 
    //html goes here 
} 

完全无效作为属性只能与类型,方法或属性相关联。 (又名...)

[MyClassAttribute] 
public class MyClass 
{ 
    [MyPropertyAttribute] 
    public int Height { get; set; } 

    [MyMethodAttribute] 
    public int GetWidth() 
    { 
    //..... 
    } 
} 

这听起来像你想封装和重用你的代码。如果是这种情况,那么你需要删除自定义属性中的大部分代码,并将其放在其他地方。例如,你可以:

public static class IPrincipleExtensions 
{ 
    public static bool HasAccess(this IPrinciple principle, IEnumerable<string> roles) 
    { 
    } 
} 

此属性是控制器

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, 
Inherited = true, 
AllowMultiple = true)] 
public class PrivilegeAttribute : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
    bool isAuthorized = base.AuthorizeCore(httpContext); 

    if (isAuthorized) 
    { 
     httpContext.Identity.HasAccess(_privilegesSplit) 
    } 

    return isAuthorized; 
} 

,虽然采用这种方式只是一个围绕黑客,你可以在视图

// something like 
@if(User.HasAccess("AdminRead, AdminWrite")) 
{ 
    //html goes here 
} 

重用PrivilegeProvider User.IsInRole真的如此,它是更多的代码来做同样的事情。

+0

感谢您的解释。 – ITWorker

相关问题