Custom Authorization (Permissions) ASP.NET MVC

社会主义新天地 提交于 2020-01-01 14:19:32

问题


In my application a role has several permissions. And I want users to have access to actions dependent on permission, not the role.

So suppose:

  • Admin has perm1, perm2, perm3,
  • SuperAdmin has all the permissons that admin has + perm4 and perm5.
  • Also, there are some minor guys also who have perm1, perm3, perm6, perm7.

I want to do the following: I want action to be accessible by guy who has suppose perm3 or perm4. those two permissions are from two different roles. but beside perm3 Admin has perm1 and perm2, this action will be also accessible by minor guys who have perm3 (its not obligatory to be admin or superadmin).

So you understand what I mean right ? I want to realise this in ASP.NET MVC 4. So I suppose I will need to make my own AuthorizeAttribute, My own IIdentity and write some methods in global.asax. There's also a Membership in ASP.NET Will I need to touch it ? I don't know how to get all things together. Can anyone help me out?


回答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:


Basically you have to create your own AuthorizeAttribute, but use IIdentity from .NET. What you have described here is a Claim based system for authentication and authorization.

Most likely you will have to throw away the Membership from ASP.NET or use just part of it. As far as I know, it is not built with claims in mind.

In .NET 4.5 the guys added the class: ClaimsPrincipal, which implements the interface IPrincipal. This class can be used to implement custom authentication and authorization based on claims.

So, when the user is authenticated, you can add the claims on the thread:

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

and then later on just use the claims you find on the Thread.CurrentPrincipal.

In ASP.NET MVC, you can do the following steps:

  1. create a Delegating Handler which authenticates the user. If the user is authenticated, then claims are added to the thread principal. Ideally, this delegating handler should be as high up the chain as possible so that you have the claims available everywhere in the execution chain. Also remember to set the HttpContext.Current.User with the same principal

    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. Create a filter which authorizes based on the claims added to the Thread Principal. Here you can do something like compare the current route with the information found in the claims.




回答3:


So i think what you says is: ActionA is accessible only if user has perm1,perm2 and similarly ActionB is accessible when user has perm1 and perm3

The code i gave is for illustration, i did not compile it. But will give you the picture of the approach i am stating

STEP 1: You can proceed with creating a permission enum attributed with Flags attribute

STEP 2: Add claims to current principal based on user permission stored in your data store.

STEP 3: When Action is invoked authorize access against claims

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

Adding claims to the 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));

check if user can access a particular action

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


来源:https://stackoverflow.com/questions/19512935/custom-authorization-permissions-asp-net-mvc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!