方法上有多个Authorization属性
本文关键字:Authorization 属性 方法 | 更新日期: 2023-09-27 18:19:35
在类方法上指定两个独立的Authorization属性时遇到问题:如果这两个属性中的任何一个为true,则允许用户访问。
Athorization类如下所示:
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class AuthAttribute : AuthorizeAttribute {
. . .
和行动:
[Auth(Roles = AuthRole.SuperAdministrator)]
[Auth(Roles = AuthRole.Administrator, Module = ModuleID.SomeModule)]
public ActionResult Index() {
return View(GetIndexViewModel());
}
有没有办法解决这个问题,或者我需要重新思考我的方法?
这将在MVC2中运行。
在asp.net的后续版本中,有一种更好的方法可以做到这一点,您可以对角色执行OR和and。这是通过约定完成的,在单个Authorize中列出多个角色将执行OR,其中添加多个Authorize属性将执行AND。
OR示例
[Authorize(Roles = "PowerUser,ControlPanelUser")]
AND示例
[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
您可以在以下链接中找到更多信息https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles
MVC处理多个AuthorizeAttribute
实例,就好像它们与AND
连接一样。如果您想要OR
行为,则需要实现自己的检查逻辑。优选地,实现AuthAttribute
以承担多个角色,并与OR
逻辑执行自己的检查。
另一个解决方案是使用标准AuthorizeAttribute
并实现自定义IPrincipal
,后者将实现bool IsInRole(string role)
方法以提供"OR"行为。
示例如下:https://stackoverflow.com/a/10754108/449906
我在生产环境中使用这个解决方案已经有一段时间了,使用的是.NET Core 3.0。我想要自定义属性和本机AuthorizeAttribute
之间的OR行为。为此,我实现了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());
}
}
只有当添加到.NET服务集合(在您的启动类中)时,才会调用此计算器,如下所示:
services.AddSingleton<IAuthorizationEvaluator, CustomAuthorizationEvaluator>();
在控制器类中,用这两个属性装饰每个方法。在我的例子中是[Authorize]
和[CustomAuthorize]
。
我不确定其他人对此有何感受,但我也想要OR
行为。在我的AuthorizationHandler
中,如果他们中的任何一个通过了,我只会打电话给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;
}
}
提供您自己的LoggedInAuthReq。在启动时用在服务中注入这些
services.AddAuthorization(o => {
o.AddPolicy("AadLoggedIn", policy => policy.AddRequirements(new LoggedInAuthReq()));
... more here
});
services.AddSingleton<IAuthorizationHandler, LoggedInHandler>();
... more here
在你的控制器方法
[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,
};
}
这可能也可以通过一个属性和一堆if
语句来实现。在这种情况下它是works for me
。asp.net核心2.2。