【问题标题】:Custom Authorization (Permissions) ASP.NET MVC自定义授权(权限)ASP.NET MVC
【发布时间】:2013-10-31 00:46:16
【问题描述】:

在我的应用程序中,一个角色有几个权限。我希望用户能够访问依赖于权限的操作,而不是角色。

所以假设:

  • 管理员拥有 perm1、perm2、perm3、
  • SuperAdmin 拥有 admin 拥有的所有权限 + perm4 和 perm5。
  • 此外,还有一些小家伙也有 perm1、perm3、perm6、perm7。

我想做以下事情:我希望拥有 perm3 或 perm4 的人可以访问操作。这两个权限来自两个不同的角色。但是除了 perm3 Admin 有 perm1 和 perm2,拥有 perm3 的未成年人也可以访问此操作(不是必须是管理员或超级管理员)。

所以你明白我的意思吧?我想在 ASP.NET MVC 4 中实现这一点。所以我想我需要创建自己的AuthorizeAttribute、我自己的IIdentity 并在 global.asax 中编写一些方法。在 ASP.NET 中还有一个 Membership 我需要触摸它吗?我不知道如何把所有的东西放在一起。谁能帮帮我?

【问题讨论】:

标签: c# asp.net-mvc authorization forms-authentication access-control


【解决方案1】:
public class PermissionAttribute : AuthorizeAttribute
    {
        private readonly IAccountService _accountService;
        private readonly IEnumerable<PermissionEnum> _permissions;

        public PermissionAttribute(params PermissionEnum[] permissions):
            this(DependencyResolver.Current.GetService<IAccountService>())
        {
            _permissions = permissions;
        }

        protected PermissionAttribute(IAccountService accountService)
        {
            _accountService = accountService;
        }

        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if(!_permissions.Any(x=>_accountService.HasPermission(filterContext.HttpContext.User.Identity.Name,(int)x)))
                filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden);
            base.OnAuthorization(filterContext);
        }

    }

【讨论】:

    【解决方案2】:

    基本上,您必须创建自己的 AuthorizeAttribute,但使用 .NET 中的 IIdentity。您在此处描述的是一个基于声明的身份验证和授权系统。

    您很可能不得不从 ASP.NET 中丢弃 Membership 或只使用其中的一部分。据我所知,它并没有考虑到声明。

    在 .NET 4.5 中,这些人添加了类:ClaimsPrincipal,它实现了接口 IPrincipal。该类可用于实现基于声明的自定义身份验证和授权。

    因此,当用户通过身份验证时,您可以在线程上添加声明:

    var id = new ClaimsIdentity(claims, "Dummy");
    var principal = new ClaimsPrincipal(new[] { id });
    Thread.CurrentPrincipal = principal;
    

    然后再使用您在 Thread.CurrentPrincipal 上找到的声明。

    在 ASP.NET MVC 中,您可以执行以下步骤:

    1. 创建一个对用户进行身份验证的委托处理程序。如果用户通过身份验证,则将声明添加到线程主体。理想情况下,这个委托处理程序应该尽可能位于链的上层,以便您在执行链中的任何地方都可以使用声明。还要记住将 HttpContext.Current.User 设置为相同的主体

      公共类 AuthHandler : DelegatingHandler{

      protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
      {
      //authenticate user
      //get claims
      //create principal
      var newPrincipal = CreatePrincipal(claims);
      Thread.CurrentPrincipal = newPrincipal;
      if (HttpContext.Current != null)
           HttpContext.Current.User = newPrincipal;
      return await base.SendAsync(request, cancellationToken);
      }
      

      }

    2. 创建一个过滤器,该过滤器根据添加到线程主体的声明进行授权。在这里,您可以将当前路线与声明中的信息进行比较。

    【讨论】:

      【解决方案3】:

      所以我认为你说的是​​:ActionA 仅在用户具有 perm1、perm2 时才可访问,类似地,当用户具有 perm1 和 perm3 时 ActionB 可访问

      我给出的代码是为了说明,我没有编译它。但是会给你我所说的方法的图片

      第 1 步:您可以继续创建带有标志属性的权限枚举

      第 2 步:根据存储在您的数据存储中的用户权限向当前委托人添加声明。

      第 3 步:当调用 Action 时,授权访问声明

      [Flags]
          enum PermType
          {
              None = 0x0,
              Perm1 = 0x1,
              perm2 = 0x2,
              perm3 = 0x4,
              perm4 = 0x8,
              perm5 = 0x10 
          }
      

      向 CurrentPrincipal 添加声明

      var currentPrincipal = ClaimsPrincipal.Current;
      var cms = currentPrincipal.Claims;
      var permissions = PermType.Perm1 | PermType.perm2;
      var claims = cms.ToList();
      claims.Add(new Claim("Action1", permissions.ToString()));
      claims.Add(new Claim("Action2", permissions.ToString()));
      claims.Add(new Claim("Action3", permissions.ToString()));
      System.Threading.Thread.CurrentPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims));
      

      检查用户是否可以访问特定操作

      public bool CanAccessThisAction(string acionName,PermType requiredPerms)
      {
          var claim = principal.Claims.FirstOrDefault(c => c.Type == acionName);
          if (customPermissionClaim != null)
          {
              //check if required permission is present in claims for this user
              //return true/false
          }
          return false;
      }
      

      关于行动

      public ActionResult TestAction(string id)
      {
          if(CanAccessThisAction("TestAction",PermType.Perm1|PermType.perm3|PermType.perm5))
          {
              //do your work here
          }
          else
          {
              //redirect user to some other page which says user is not authorized
          }
      }
      

      【讨论】:

      猜你喜欢
      • 2010-11-01
      • 2013-12-14
      • 2010-09-30
      • 1970-01-01
      • 2019-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多