Pass parameters to a Requirement/Policy in ASP.NET MVC 6

馋奶兔 提交于 2019-12-08 19:16:38

问题


I was trying to make a custom authorization attribute in ASP.NET vNext, until I found this excelent answer from @blowdart in this post:

https://stackoverflow.com/a/31465227/1756978

indicating that Authorization requirements is now the way to go. The answer is very clarifying but doesn't indicates how to pass a parameter to this requirements / policies.

What I'm trying to do is porting a MVC 5 custom authorization attribute which has this signature:

[Autorizacion(Requires = enumPermission.DeleteCustomer)]

since I use a very customised set of permissions mirrored in the backend/frontend as enums/strings.

As this features are still not documented I feel a little lost... Could anybody give guidance about?

Thanks in advance


回答1:


Indeed, @blowdart’s post is very insightful and from my understanding, the key thing to understand is the following:

Authorization act upon Identities. Identities are created by authentication.

So it seems that identities are created by the authentication process.

Then (if you wish) you can make the authorization process kick in. This means creating a custom authorization requirements to which this requirement will be looking at those identities and act upon them.

In plain English, this is what I believe is happening:

  1. As mentioned in blowdart’s post, we should have some sort of authentication middleware that happens to do the actual authentication. Once successfully authenticated, you take whatever information you want from that now-authenticated user and create an authenticated ClaimsPrincipal.

    For example, we could store into that ClaimsPrincipal, the sets of permission the user has.

  2. Then, when you create your authorization requirement you look at the ClaimsPrincipal, extract the sets of permissions from the ClaimsPrincipal and take appropriate action based on whatever business rules you want.

    Assuming you can’t store the sets of permission into the ClaimsPrincipal for some reason, one could easily store the UserId and from within the requirement, read that UserId from the ClaimsPrincipal, invoke the database and get the sets of permissions and then act upon them.

Conclusion:

So in short, I don’t think you pass stuff to the requirement(s), I think you obtain them from within a ClaimsPrincipal.

In your example, you could create a requirement that reads the ClaimsPrincipal and compare whatever value with your Enum and act upon that.

Let us know what you’ve managed to do and if it works.

And if my understanding of this is wrong, then by all means, feel free to correct me since all of this is new stuff :-)




回答2:


I happen to comes up with a workround that can satisfy my requirement, hope it will help your too.

In my case, I need to pass IHttpContextAccessor and EFCore's AppDbContext to my Requirement class.

in my Startup.cs, I write something like this:

services.AddAuthorization(options =>
{
    options.AddPolicy("ThePolicy", policy => policy.Requirements.Add( new ThePolicyRequirement() ));
});
services.AddScoped<IAuthorizationHandler, ThePolicyAuthorizationHandler>();

the ThePolicyAuthorizationHandler class:

public class ThePolicyAuthorizationHandler : AuthorizationHandler<ThePolicyRequirement>
{
    readonly AppDbContext _appContext;
    readonly IHttpContextAccessor _contextAccessor;

    public ThePolicyAuthorizationHandler(AppDbContext c, IHttpContextAccessor ca)
    {
        _appContext = c;
        _contextAccessor = ca;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ThePolicyRequirement requirement)
    {
        var result = await requirement.isPass(_appContext, _contextAccessor, context);
        if (result)
            context.Succeed(requirement);
        else
            context.Fail(requirement);
    }
}

and ThePolicyRequirement class:

public class ThePolicyRequirement : IAuthorizationRequirement
{
    AppDbContext _context;
    IHttpContextAccessor _contextAccessor;
    AuthorizationHandlerContext _authHandlerContext;

    public async Task<bool> isPass(AppDbContext context, IHttpContextAccessor contextAccessor, AuthorizationHandlerContext authorizationHandlerContext)
    {
        _context = context;
        _contextAccessor = contextAccessor;
        _authHandlerContext = authorizationHandlerContext;

        //logic here

        return result;
    }
}

The key idea is using ThePolicyAuthorizationHandler to obtain as much as possible all needed objects, and pass it to ThePolicyRequirementto do the logic of the authorization mechanism.



来源:https://stackoverflow.com/questions/32181400/pass-parameters-to-a-requirement-policy-in-asp-net-mvc-6

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