自定义授权(权限)ASP.NET MVC

时间:2013-10-22 08:37:55

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

在我的应用程序中,角色具有多个权限。我希望用户可以访问依赖于权限的操作,而不是角色。

所以假设:

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

我想做以下事情:我希望有假设perm3或perm4的人可以访问操作。这两个权限来自两个不同的角色。但是除了perm3 Admin有perm1和perm2之外,这个动作也可以由具有perm3的小家伙访问(不一定是admin或superadmin)。

所以你明白我的意思吧?我想在ASP.NET MVC 4中实现这一点。所以我想我需要创建自己的AuthorizeAttribute,我自己的IIdentity并在global.asax中编写一些方法。 ASP.NET中还有一个成员资格我是否需要触摸它?我不知道如何把所有的东西放在一起。任何人都可以帮助我吗?

3 个答案:

答案 0 :(得分: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);
        }

    }

答案 1 :(得分:1)

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

您很可能不得不从ASP.NET中删除成员身份或仅使用其中的一部分。据我所知,它并没有考虑到索赔。

在.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

    public class 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. 创建一个过滤器,根据添加到Thread Principal的声明进行授权。在这里,您可以执行诸如将当前路线与声明中的信息进行比较。

答案 2 :(得分:0)

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

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

第1步:您可以继续创建使用Flags属性归属的权限枚举

第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;
}

on Action

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
    }
}