2010-02-19 123 views
4

如果我想只有管理員才能訪問名爲「ManagerUser」的動作,我知道我能做到這一點:ASP .NET MVC保護控制器/動作

[Authorize(Roles = Constants.ROLES_ADMINISTRATOR)] 
public ActionResult ManageUser(string id) 
{ 
} 

如果我想給除了大家訪問管理員?我不想在函數中編寫所有角色:|。

任何建議/出路?

回答

11

您可以創建自己的自定義授權屬性,如「AuthorizeAllExceptAdmin」。在這個類中,你只需要檢查當前用戶是否是管理員,如果他們拒絕它,否則接受它。

這裏有一個很好的tutorial,但你可能會喜歡的東西最終會:

public class AuthorizeAllExceptAdmin : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     return !httpContext.User.IsInRole(Constants.ROLES_ADMINISTRATOR); 
    } 
} 

那麼你的控制器的方法變爲:

[AuthorizeAllExceptAdmin] 
public ActionResult SomethingOnlyNonAdminsCanDo() 
{ 
} 

下面是需要自定義屬性的示例角色否認。

public class DoNotAuthorize : AuthorizeAttribute 
{ 
    private IEnumerable<string> _rolesToReject; 

    public DoNotAuthorize(IEnumerable<string> rolesToReject) 
    { 
     _rolesToReject = rolesToReject;   
    } 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     foreach (var role in _rolesToReject) 
     { 
      if (httpContext.User.IsInRole(role)) 
       return false; 
     } 

     return true; 
    } 
} 

那麼你的控制器的方法變爲:

[DoNotAuthorize(new [] {Constants.ROLES_ADMINISTRATOR})] 
public ActionResult SomethingOnlyNonAdminsCanDo() 
{ 
} 

我會考慮一些問題,它選擇上述選項之一之前。如果您認爲您將擁有多個具有類似授權要求的方法(或者整個控制器)(即管理員無法執行的多個操作),那麼我會堅持使用非參數化的自定義屬性。這樣,您可以稍後一起演變它們(僅更改自定義屬性)。例如,也許稍後您希望管理員能夠進入特殊模式,在這些模式下他們可以執行這些操作。或者,如果行動中的自動化程度更加不同,那麼使用參數化列表是有意義的,因爲它們將相對獨立地進化。

+0

任何意見;我怎麼能傳遞多個參數到自定義屬性?像[DoNotAuthorize(role ='A',role ='B')]? – effkay 2010-02-19 17:29:23

+0

@effkay是的,你只需在構造函數中包含那些用於定製屬性的元素。我將在上面添加一個示例。 – manu08 2010-02-19 17:44:36

+0

不錯的例子。使用IEnumerable,類似於我先前提出的IList。這樣你就可以擁有儘可能多的拒絕角色。 – 2010-02-20 16:52:38

5

除了創建自定義AuthorizeAttribute,馬努建議,你可以使用的PrincipalPermission,有Deny-SecurityAction:

[PrincipalPermission(SecurityAction.Deny, Role="Administrator")] 
+0

謝謝... lemme試試! – effkay 2010-02-19 17:08:02

+0

這是一個很好的觀點。我想用自定義屬性來做這件事的主要原因是爲了以後更容易維護。例如,如果您決定稍後拒絕另一個角色,則只需修改自定義屬性,而不是修改使用解決方案的每個單獨方法。 – manu08 2010-02-19 17:09:11

+0

是的,我猜...還有,[PrincipalPermission(SecurityAction.Deny,Role =「Administrator」)]沒有工作..... – effkay 2010-02-19 17:12:25

1

在我的應用程序,所以我要查詢數據庫,以確定我不使用角色用戶是否有權訪問。以下代碼的好處是您可以非常輕鬆地將用戶重定向到某個操作。我在我的博客文章在http://blog.athe.la/2009/12/implementing-permission-via-windows-authentication-in-asp-mvc-using-action-filters/解釋代碼

public class DatabaseRepository() 
{ 
    private readonly DatabaseDataContext db = new DatabaseDataContext(); 

    public bool UserHasPermission(string userLogon) { 
     return (from permission this.db.Permissions 
       where permission.HasPermissionSw == true 
       select permission).Contains(userLogon); 
    } 
} 

public class UserHasPermission: ActionFilterAttribute 
{ 
    private readonly DatabaseRepository databaseRepository = new DatabaseRepository(); 
    private readonly string redirectAction; 
    public UserHasPermission(string redirectTo) 
    { 
     this.redirectAction = redirectTo; 
    } 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     string userLogon = filterContext.HttpContext.User.Identity.Name; 
     if (!this.databaseRepository.UserHasPermission(userLogon)) 
     { 
      string routeController = filterContext.Controller.ControllerContext.RouteData.Values["controller"]; 
      filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = routeController, action = this.redirectAction })); 
     } 
    } 
} 

你的控制器,然後會是這個樣子:

[UserHasPermission("NoAccess")] 
public ActionResult SecretArea() 
{ 
    // run all the logic 
    return View(); 
} 

public ActionResult NoAccess() 
{ 
    return View(); 
}