简体   繁体   English

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

[英]Custom Authorization (Permissions) ASP.NET MVC

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, 管理员有perm1,perm2,perm3,
  • SuperAdmin has all the permissons that admin has + perm4 and perm5. SuperAdmin拥有管理员拥有的所有权限+ perm4和perm5。
  • Also, there are some minor guys also who have perm1, perm3, perm6, perm7. 此外,还有一些小家伙也有perm1,perm3,perm6,perm7。

I want to do the following: I want action to be accessible by guy who has suppose perm3 or perm4. 我想做以下事情:我想让那些假设perm3或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). 但是除了perm3 Admin有perm1和perm2之外,这个动作也可以由具有perm3的小家伙访问(不一定是admin或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. 我想在ASP.NET MVC 4中实现这一点。所以我想我需要创建自己的AuthorizeAttribute ,我自己的IIdentity并在global.asax中编写一些方法。 There's also a Membership in ASP.NET Will I need to touch it ? ASP.NET中还有一个成员资格我是否需要触摸它? I don't know how to get all things together. 我不知道如何把所有的东西放在一起。 Can anyone help me out? 谁能帮我吗?

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

    }

Basically you have to create your own AuthorizeAttribute, but use IIdentity from .NET. 基本上你必须创建自己的AuthorizeAttribute,但是使用.NET中的IIdentity。 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. 很可能您将不得不从ASP.NET中丢弃成员资格或仅使用其中的一部分。 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. 在.NET 4.5中,这些人添加了类:ClaimsPrincipal,它实现了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. 然后再使用你在Thread.CurrentPrincipal上找到的声明。

In ASP.NET MVC, you can do the following steps: 在ASP.NET MVC中,您可以执行以下步骤:

  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 还记得使用相同的主体设置HttpContext.Current.User

    public class AuthHandler : DelegatingHandler{ 公共类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. 创建一个过滤器,根据添加到Thread Principal的声明进行授权。 Here you can do something like compare the current route with the information found in the claims. 在这里,您可以执行诸如将当前路线与声明中的信息进行比较之类的操作。

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 所以我认为你说的是​​:只有当用户有perm1,perm2时才能访问ActionA,当用户有perm1和perm3时,类似的ActionB是可访问的

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 步骤1:您可以继续创建使用Flags属性归属的权限枚举

STEP 2: Add claims to current principal based on user permission stored in your data store. 第2步:根据存储在数据存储中的用户权限向当前主体添加声明。

STEP 3: When Action is invoked authorize access against claims 第3步:调用Action时,授权访问声明

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

Adding claims to the CurrentPrincipal 将声明添加到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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM