【问题标题】:Optimize Roles authorization in ASP.NET MVC优化 ASP.NET MVC 中的角色授权
【发布时间】:2017-07-13 15:04:44
【问题描述】:

我正在为我的公司创建一个 asp.NET MVC5 内网网站,并且由于我刚刚根据 Active Directory 中的用户角色实现了授权和动态菜单,因此我需要应用访问限制。我在 MSDN / Technet 上读到,您可以使用 [Authorize(Role="<YourRole>")] 申请授权,我让它完美运行。现在我的问题是我有 20 个不同的角色,每个角色都与我的 MSSQL 数据库中的 DocumentsCategories 链接。这意味着如果你想访问一个文档或资源,你必须首先在数据库中找到相应的条目(如果你需要我可以进一步解释)。因此,如果我使用[Authorize] 属性实现授权,我将不得不检查我的数据库以查看该行是否存在,以及是否添加它。我已经开始使用静态类来做到这一点:

public static class CustomRoles
{
    public const string Role1 = "Role1";
    public const string Role2 = "Role2";
    //And so on ...
}

然后在我的控制器操作方法中:

[Authorize(Roles=CustomRoles.Role1+","+CustomRoles.Role2)]
public ActionResult Index(){}

您可以想象,为每个角色执行此操作将是漫长而乏味的。

所以我的问题:你知道有什么更好/更简单的方法吗?因为我必须手动检查每个文档(数千个!)然后在另一个表中查看关联的配置文件,然后应用相应的授权。从技术上讲,我的动态菜单应该可以解决这个问题,因为您看不到您无法使用的内容,但话又说回来,如果未实施授权,您可以使用 URL 以这种方式访问​​任何内容

另外:并非所有角色都在我的数据库中注册,大多数用户有大约 140 个角色,但可能只有 1 或 2 个在数据库中注册。这会产生一些性能问题吗?我知道当我创建 Claims 并过滤掉不属于数据库的那些时我可以处理这个问题,但我不想这样做。

【问题讨论】:

  • 我不明白你到底想要什么,但我想我有你的问题。您需要一个自定义授权属性。请查看此帖子diaryofaninja.com/blog/2011/07/24/… 它教如何编写自定义帖子。

标签: c# asp.net-mvc active-directory owin


【解决方案1】:

您可以做的一种解决方法是在ActionFilter 中使用覆盖的OnActionExecuting 方法而不是装饰器AuthorizeAttribute 来检查用户是否被授权执行某些操作。

是的,你仍然需要仔细检查你的角色授权,但不是稀疏,因为你只需要检查所有one 位置,即您的操作过滤器(或者更准确地说,您的 single switch)。此外,将所有内容放在一个地方可以让您避免冗余并尽可能使逻辑更紧凑。

例子:

ActionFilter

public class AuthorizeActionFilterAttribute : ActionFilterAttribute {
    public override void OnActionExecuting(ActionExecutingContext filterContext) {

        IPrincipal user = HttpContext.Current.User; //get the current user

        //Get controller name and action
        string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
        string actionName = filterContext.ActionDescriptor.ActionName;

        //All roles will be defined here!
        List<string> rolesAccepted = new List<string>();
        switch (controllerName){
            case "Controller1": //suppose these three happen to have the same rules
            case "Controller2":
            case "Controller3":
                //Describe roles accepted for certain controller and action
                rolesAccepted = new List<string> { "Role1", "Role2" };            
                break;
            case "Controller4": //suppose these have specific restrictions only for some actions
                if (actionName == "action1") {//can also use switch 
                    rolesAccepted = new List<string> { "Role3", "Role4" };
                } else {
                    rolesAccepted = new List<string> { "Role5", "Role6", "Role7" };
                }
                break;
            ....
        }

        //Redirect to login if non of the user role is authorized
        if (!rolesAccepted.Any(x => user.IsInRole(x)){
            filterContext.Result = redirectToLogin();
            return;
        }
    }

    private ActionResult redirectToLogin() {
      return new RedirectToRouteResult(
          new RouteValueDictionary(new { controller = "Account", action = "Login" })
        );
    }

}

然后您只需将AuthorizeActionFilterAttribute 放在每个控制器中(而不是每个操作中的角色),因为您已经在一个地方处理了所有授权:

[AuthorizeActionFilter]
public class Controller1 : Controller {
    ...
}

[AuthorizeActionFilter]
public class Controller2 : Controller {
    ...
}

... and so on

【讨论】:

  • 啊,太好了!这就是我一直在寻找的,我会测试它并在我让它工作后标记为答案,谢谢!
  • @LéonardLaiter 欢迎您。请检查一下!
  • 很高兴知道这一点!
猜你喜欢
  • 2010-10-21
  • 2021-09-04
  • 1970-01-01
  • 2011-09-03
  • 1970-01-01
  • 1970-01-01
  • 2014-05-08
  • 2015-09-15
  • 1970-01-01
相关资源
最近更新 更多