问题
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:
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.Then, when you create your
authorization requirement
you look at theClaimsPrincipal
, extract the sets of permissions from theClaimsPrincipal
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 theClaimsPrincipal
, 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 ThePolicyRequirement
to do the logic of the authorization mechanism.
来源:https://stackoverflow.com/questions/32181400/pass-parameters-to-a-requirement-policy-in-asp-net-mvc-6