2016-08-15 55 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

相關問題