2010-02-19 85 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(); 
}