C# 方法上的多个授权属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17272422/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multiple Authorization attributes on method
提问by adamse
I'm having trouble specifying two separate Authorization attributes on a class method: the user is to be allowed access if either of the two attributes are true.
我在类方法上指定两个单独的授权属性时遇到问题:如果两个属性中的任何一个为真,则允许用户访问。
The Athorization class looks like this:
Athorization 类如下所示:
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class AuthAttribute : AuthorizeAttribute {
. . .
and the action:
和行动:
[Auth(Roles = AuthRole.SuperAdministrator)]
[Auth(Roles = AuthRole.Administrator, Module = ModuleID.SomeModule)]
public ActionResult Index() {
return View(GetIndexViewModel());
}
Is there a way to solve this or do I need to rethink my approach?
有没有办法解决这个问题,或者我需要重新考虑我的方法吗?
This is to be run in MVC2.
这将在 MVC2 中运行。
采纳答案by Jakub Konecki
Multiple AuthorizeAttributeinstances are processed by MVC as if they were joined with AND. If you want an ORbehaviour you will need to implement your own logic for checks. Preferably implement AuthAttributeto take multiple roles and perform an own check with ORlogic.
AuthorizeAttributeMVC 处理多个实例,就好像它们与AND. 如果你想要一个OR行为,你需要实现你自己的检查逻辑。最好实现AuthAttribute承担多个角色并使用OR逻辑执行自己的检查。
Another solution is to use standard AuthorizeAttributeand implement custom IPrincipalthat will implement bool IsInRole(string role)method to provide 'OR' behaviour.
另一种解决方案是使用标准AuthorizeAttribute并实现自定义IPrincipal,以实现bool IsInRole(string role)提供“或”行为的方法。
An example is here: https://stackoverflow.com/a/10754108/449906
回答by Daxxy
There is a better way to do this in later versions of asp.net you can do both OR and AND on roles. This is done through convention, listing multiple roles in a single Authorize will perform an OR where adding Multiple Authorize Attributes will perform AND.
在更高版本的 asp.net 中有更好的方法来执行此操作,您可以对角色执行 OR 和 AND。这是通过约定完成的,在单个授权中列出多个角色将执行 OR,其中添加多个授权属性将执行 AND。
OR example
或示例
[Authorize(Roles = "PowerUser,ControlPanelUser")]
AND Example
AND 示例
[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
You can find more info on this at the following link https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles
您可以在以下链接中找到更多信息 https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles
回答by No Refunds No Returns
I'm not sure how others feel about this but I wanted an ORbehavior too. In my AuthorizationHandlers I just called Succeedif any of them passed. Note this did NOT work with the built-in Authorizeattribute that has no parameters.
我不确定其他人对此有何看法,但我也想要一种OR行为。在我的AuthorizationHandlers 我只是打电话,Succeed如果他们中的任何一个通过。请注意,这不适Authorize用于没有参数的内置属性。
public class LoggedInHandler : AuthorizationHandler<LoggedInAuthReq>
{
private readonly IHttpContextAccessor httpContextAccessor;
public LoggedInHandler(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, LoggedInAuthReq requirement)
{
var httpContext = httpContextAccessor.HttpContext;
if (httpContext != null && requirement.IsLoggedIn())
{
context.Succeed(requirement);
foreach (var req in context.Requirements)
{
context.Succeed(req);
}
}
return Task.CompletedTask;
}
}
Supply your own LoggedInAuthReq. In startup inject these in services with
提供您自己的 LoggedInAuthReq。在启动时将这些注入到服务中
services.AddAuthorization(o => {
o.AddPolicy("AadLoggedIn", policy => policy.AddRequirements(new LoggedInAuthReq()));
... more here
});
services.AddSingleton<IAuthorizationHandler, LoggedInHandler>();
... more here
And in your controller method
在你的控制器方法中
[Authorize("FacebookLoggedIn")]
[Authorize("MsaLoggedIn")]
[Authorize("AadLoggedIn")]
[HttpGet("anyuser")]
public JsonResult AnyUser()
{
return new JsonResult(new { I = "did it with Any User!" })
{
StatusCode = (int)HttpStatusCode.OK,
};
}
This could probably also be accomplished with a single attribute and a bunch of ifstatements. It works for mein this scenario. asp.net core 2.2 as of this writing.
这可能也可以通过单个属性和一堆if语句来完成。它works for me在这种情况下。在撰写本文时,asp.net core 2.2。
回答by Ceres Rohana
I've been using this solution in production environment for awhile now, using .NET Core 3.0. I wanted the OR behavior between a custom attributeand the native AuthorizeAttribute. To do so, I implemented the IAuthorizationEvaluatorinterface, which gets called as soon as all authorizers evaluate theirs results.
我已经在生产环境中使用这个解决方案有一段时间了,使用 .NET Core 3.0。我想要自定义属性和本机AuthorizeAttribute. 为此,我实现了IAuthorizationEvaluator接口,一旦所有授权人评估他们的结果,就会调用该接口。
/// <summary>
/// Responsible for evaluating if authorization was successful or not, after execution of
/// authorization handler pipelines.
/// This class was implemented because MVC default behavior is to apply an AND behavior
/// with the result of each authorization handler. But to allow our API to have multiple
/// authorization handlers, in which the final authorization result is if ANY handlers return
/// true, the class <cref name="IAuthorizationEvaluator" /> had to be extended to add this
/// OR behavior.
/// </summary>
public class CustomAuthorizationEvaluator : IAuthorizationEvaluator
{
/// <summary>
/// Evaluates the results of all authorization handlers called in the pipeline.
/// Will fail if: at least ONE authorization handler calls context.Fail() OR none of
/// authorization handlers call context.Success().
/// Will succeed if: at least one authorization handler calls context.Success().
/// </summary>
/// <param name="context">Shared context among handlers.</param>
/// <returns>Authorization result.</returns>
public AuthorizationResult Evaluate(AuthorizationHandlerContext context)
{
// If context.Fail() got called in ANY of the authorization handlers:
if (context.HasFailed == true)
{
return AuthorizationResult.Failed(AuthorizationFailure.ExplicitFail());
}
// If none handler called context.Fail(), some of them could have called
// context.Success(). MVC treats the context.HasSucceeded with an AND behavior,
// meaning that if one of the custom authorization handlers have called
// context.Success() and others didn't, the property context.HasSucceeded will be
// false. Thus, this class is responsible for applying the OR behavior instead of
// the default AND.
bool success =
context.PendingRequirements.Count() < context.Requirements.Count();
return success == true
? AuthorizationResult.Success()
: AuthorizationResult.Failed(AuthorizationFailure.ExplicitFail());
}
}
This evaluator will only be called if added to .NET service collection (in your startup class) as follows:
仅当添加到 .NET 服务集合(在您的启动类中)时才会调用此评估器,如下所示:
services.AddSingleton<IAuthorizationEvaluator, CustomAuthorizationEvaluator>();
In the controller class, decorate each method with both attributes. In my case [Authorize]and [CustomAuthorize].
在控制器类中,用这两个属性装饰每个方法。在我的情况[Authorize]和[CustomAuthorize].

