2014-02-06 36 views
1

限制访问控制器的正确方法是什么?根据某些条件限制对控制器的访问权限,而不是用户身份验证

例如,我可能有“ProductReviewController”,我希望能够检查该控制器是否可在当前存储中访问并启用。我不是在代码之后做这件事,而是对如果不符合这个标准而停止用户进入控制器的方法感兴趣。我希望这个请求能够继续进行,就好像控制器从不在那里一样(所以也许扔404)。

我的想法至今:

  1. 数据注解即[IsValidController]。哪个Attribute类会从我派生 - 授权似乎并不适合,我会将此与用户身份验证相关联。另外,如果不符合标准,我不确定正确的答案是什么(但我想这取决于它来自于Attribute)。我可以把这个数据注释对我的基础控制器。

  2. 找到页面生命周期中较低的位置,并且如果控制器不符合我的标准,则停止用户点击控制器。即创建我自己的控制器厂在7点这里描述:http://blogs.msdn.com/b/varunm/archive/2013/10/03/understanding-of-mvc-page-life-cycle.aspx

,这是什么最好的方法?

注意:目前,我倾向于选项1,并使用AuthorizeAttribute,其代码如下所示。虽然我觉得我滥用AuthorizeAttribute

public class IsControllerAccessible : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     if (!CriteriaMet()) 
      return false; 

     return true; 
    } 

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     filterContext.Result = new RedirectToRouteResult(
     new RouteValueDictionary(
      new 
      { 
       controller = "Generic", 
       action = "404" 
      }) 
     ); 
    } 
} 

回答

3

我觉得你对AuthorizeAttribute感到困惑。它是一个动作过滤器,而不是数据注释。 Data Annotations为validatioj装饰模型属性,Action Filter的装饰控制器动作检查控制器的上下文并在动作执行之前执行某些操作。

因此,限制对控制器动作的访问权限是AuthorizeAttribute的存在条件,所以让我们使用它!

随着SO的好乡亲的帮助下,我创建了限制访问基于访问Directory组被部分行动(甚至控制器)用户行为过滤器:

public class AuthorizeADAttribute : AuthorizeAttribute 
{ 
    public string Groups { get; set; } 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     if (base.AuthorizeCore(httpContext)) 
     { 
      /* Return true immediately if the authorization is not 
      locked down to any particular AD group */ 
      if (String.IsNullOrEmpty(Groups)) 
       return true; 

      // Get the AD groups 
      var groups = Groups.Split(',').ToList<string>(); 

      // Verify that the user is in the given AD group (if any) 
      var context = new PrincipalContext(ContextType.Domain, "YOURADCONTROLLER"); 
      var userPrincipal = UserPrincipal.FindByIdentity(context, 
               IdentityType.SamAccountName, 
               httpContext.User.Identity.Name); 

      foreach (var group in groups) 
      { 
       try 
       { 
        if (userPrincipal.IsMemberOf(context, IdentityType.Name, group)) 
         return true; 
       } 
       catch (NoMatchingPrincipalException exc) 
       { 
        var msg = String.Format("While authenticating a user, the operation failed due to the group {0} could not be found in Active Directory.", group); 
        System.ApplicationException e = new System.ApplicationException(msg, exc); 
        ErrorSignal.FromCurrentContext().Raise(e); 
        return false; 
       } 
       catch (Exception exc) 
       { 
        var msg = "While authenticating a user, the operation failed."; 
        System.ApplicationException e = new System.ApplicationException(msg, exc); 
        ErrorSignal.FromCurrentContext().Raise(e); 
        return false; 
       } 
      } 
     } 
     return false; 
    } 
} 

注意这将返回一个401 Unauthorized,这是有道理的,而不是你上面指出的404 Not Found。现在

,在这个神奇的是,你可以通过在操作层面将它限制访问:

[AuthorizeAD(Groups = "Editor,Contributer")] 
public ActionResult Create() 

或者在控制器级别:

[AuthorizeAD(Groups = "Admin")] 
public class AdminController : Controller 

甚至在编辑FilterConfig.cs全球`/ App_Start':

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new HandleErrorAttribute()); 
     filters.Add(new Code.Filters.MVC.AuthorizeADAttribute() { Groups = "User, Editor, Contributor, Admin" }); 
    } 

完全真棒酱!

P.S.你在第二点提到页面生命周期。在MVC中没有这样的事情,至少在Web Forms的意义上你不会想到。这对我来说是件好事,因为事情大大简化了,我不必记住十几种不同的生命周期事件以及他们每一个人都被提出来的东西!

+0

好的,谢谢你对数据注释的澄清 - 我的术语错了。我刚刚使用'AuthorizeAttribute'编写了自己的版本,并且运行良好。我只是想确保这是正确的方式。当我提到生命周期时,我指的是这种事情:http://blogs.msdn.com/b/varunm/archive/2013/10/03/understanding-of-mvc-page-life-cycle。 ASPX。我特别想到重申第7点并创建一个定制控制器工厂。 – webnoob

+0

p.s'404 not found'在我的情况下是正确的答案。不是未经授权的用户,而是不应该显示内容的站点(这意味着用户需要跟踪缓存的链接或其他内容)。 – webnoob

+0

然后代码应该可能驻留在您的控制器本身,因为它负责根据用户交互提供正确的视图。如果用户提供产品ID,请让控制器检查存储中是否存在该产品,如果不存在,则重定向到指示这样的特定视图。 –

相关问题