56

我在类方法上指定两个单独的授权属性时遇到问题:如果两个属性中的任何一个为真,则允许用户访问。

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 中运行。

4

4 回答 4

74

在更高版本的 asp.net 中有更好的方法来执行此操作,您可以对角色执行 OR 和 AND。这是通过约定完成的,在单个授权中列出多个角色将执行 OR,其中添加多个授权属性将执行 AND。

或示例

[Authorize(Roles = "PowerUser,ControlPanelUser")] 

与示例

[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]

您可以在以下链接中找到更多信息 https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles

于 2016-09-12T08:27:45.113 回答
43

多个AuthorizeAttribute实例由 MVC 处理,就好像它们与AND. 如果你想要一个OR行为,你需要实现你自己的检查逻辑。最好实现AuthAttribute承担多个角色并使用OR逻辑执行自己的检查。

另一种解决方案是使用标准AuthorizeAttribute并实现自定义IPrincipal,这将实现bool IsInRole(string role)提供“或”行为的方法。

一个例子在这里: https ://stackoverflow.com/a/10754108/449906

于 2013-06-24T09:46:02.277 回答
5

我已经在生产环境中使用这个解决方案一段时间了,使用 .NET Core 3.0。我想要自定义属性和 native之间的 OR 行为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());
    }
}

仅当添加到 .NET 服务集合(在您的启动类中)时,才会调用此评估器,如下所示:

services.AddSingleton<IAuthorizationEvaluator, CustomAuthorizationEvaluator>();

在控制器类中,用两个属性装饰每个方法。就我而言[Authorize],并且[CustomAuthorize].

于 2020-04-17T22:32:17.980 回答
2

我不确定其他人对此有何看法,但我OR也想要一种行为。如果他们中的任何一个通过了,我AuthorizationHandler就打电话给我SucceedAuthorize请注意,这不适用于没有参数 的内置属性。

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 core 2.2。

于 2019-07-26T18:24:56.940 回答