web-dev-qa-db-fra.com

Attributs d'autorisation multiples sur la méthode

J'ai du mal à spécifier deux attributs d'autorisation distincts sur une méthode de classe: l'utilisateur doit être autorisé à accéder si l'un des deux attributs est vrai.

La classe d'athorisation ressemble à ceci:

[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class AuthAttribute : AuthorizeAttribute {
. . .

et l'action:

[Auth(Roles = AuthRole.SuperAdministrator)]
[Auth(Roles = AuthRole.Administrator, Module = ModuleID.SomeModule)]
public ActionResult Index() {
    return View(GetIndexViewModel());
}

Existe-t-il un moyen de résoudre ce problème ou dois-je repenser mon approche?

Il doit être exécuté dans MVC2.

33
adamse

Plusieurs instances AuthorizeAttribute sont traitées par MVC comme si elles étaient jointes à AND. Si vous voulez un comportement OR, vous devrez implémenter votre propre logique pour les vérifications. Implémentez de préférence AuthAttribute pour jouer plusieurs rôles et effectuer votre propre vérification avec la logique OR.

Une autre solution consiste à utiliser AuthorizeAttribute standard et à implémenter IPrincipal personnalisé qui implémentera la méthode bool IsInRole(string role) pour fournir un comportement 'OU'.

Un exemple est ici: https://stackoverflow.com/a/10754108/449906

31
Jakub Konecki

Il existe une meilleure façon de le faire dans les versions ultérieures d'asp.net, vous pouvez faire les deux OR et AND sur les rôles. Cela se fait par convention, répertorier plusieurs rôles dans une seule autorisation effectuera une OR où l'ajout de plusieurs attributs d'autorisation effectuera AND.

OU exemple

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

ET Exemple

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

Vous pouvez trouver plus d'informations à ce sujet sur le lien suivant https://docs.Microsoft.com/en-us/aspnet/core/security/authorization/roles

45
Daxxy

Je ne sais pas trop ce que les autres pensent de cela, mais je voulais aussi un comportement OR. Dans mes AuthorizationHandlers, je viens d'appeler Succeed si l'un d'entre eux a réussi. Notez que cela n'a PAS fonctionné avec l'attribut Authorize intégré qui n'a pas de paramètres.

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;
    }
}

Fournissez votre propre LoggedInAuthReq. Au démarrage, injectez-les dans les services avec

        services.AddAuthorization(o => {
            o.AddPolicy("AadLoggedIn", policy => policy.AddRequirements(new LoggedInAuthReq()));
            ... more here
        });
        services.AddSingleton<IAuthorizationHandler, LoggedInHandler>();
        ... more here

Et dans votre méthode de contrôleur

    [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,
        };
    }

Cela pourrait probablement aussi être accompli avec un seul attribut et un tas d'instructions if. Il works for me dans ce scénario. asp.net core 2.2 au moment de la rédaction de cet article.

0