web-dev-qa-db-fra.com

Autoriser l'attribut avec plusieurs rôles

J'aimerais ajouter une autorisation à un contrôleur, pour plusieurs rôles à la fois.

Normalement, cela ressemblerait à ceci:

[Authorize(Roles = "RoleA,RoleB,RoleC")]
public async Task<ActionResult> Index()
{
}

Mais j'ai stocké mes rôles dans les consts, car ils pourraient changer ou être étendus à un moment donné.

public const RoleA = "RoleA";
public const RoleB = "RoleB";
public const RoleC = "RoleC";

Je ne peux pas faire cela, car la chaîne doit être connue au moment de la compilation:

[Authorize(Roles = string.join(",",RoleA,RoleB,RoleC)]
public async Task<ActionResult> Index()
{
}

Y a-t-il un moyen de contourner le problème?

Je pourrais écrire un const qui contient simplement "RoleA, RoleB, RoleC" - mais je n'aime pas les chaînes magiques et c'est une chaîne magique. Changer le nom d'un rôle et oublier de changer la chaîne combinée serait un désastre.

J'utilise MVC5. L'identité ASP.NET et le rôle sont connus au moment de la compilation.

76
Christian Sauer

Essayez de créer un attribut authorize personnalisé tel que this .

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    public AuthorizeRolesAttribute(params string[] roles) : base()
    {
        Roles = string.Join(",", roles);
    }
}

En supposant que vos rôles soient identiques pour plusieurs contrôleurs, créez une classe d'assistance:

public static class Role
{
    public const string Administrator = "Administrator";
    public const string Assistant = "Assistant";
}

Alors utilisez-le comme suit:

public class MyController : Controller
{
    [AuthorizeRoles(Role.Administrator, Role.Assistant)]
    public ActionResult AdminOrAssistant()
    {                       
        return View();
    }
}
146
MacGyver

Assurez-vous que vous dérivez votre classe d'attributs personnalisée avec System.Web.Mvc.AuthorizeAttribute et NOT System.Web.Http.AuthorizeAttribute.

J'ai rencontré le même problème. Une fois que j'ai changé, tout a fonctionné.

Vous pouvez également ajouter les éléments suivants à votre classe d'attributs personnalisés:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 
8
Jerry Finegan

La méthode la plus simple et la plus simple que j'ai trouvée pour résoudre ce problème consiste à concaténer des rôles dans l'attribut Autoriser.

[Authorize(Roles = CustomRoles.Admin + "," + CustomRoles.OtherRole)]

avec CustomRole une classe avec des chaînes constantes comme celle-ci: 

public static class CustomRoles
{
    public const string Admin = "Admin";
    // and so on..
}
6
ChristopheHvd

Ce que j'ai fait est la réponse dans @Tieson

Je tweak un peu dans sa réponse. Au lieu de string.Join, pourquoi ne pas le convertir en liste?

Voici ma réponse:

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    private new List<string> Roles;
    public AuthorizeRolesAttribute(params string[] roles) : base()
    {
        Roles = roles.toList()
    }
}

Et ensuite, vérifiez si le rôle est valide en remplaçant OnAuthorization

public override void OnAuthorization(HttpActionContext actionContext)
{
            if (Roles == null)
                HandleUnauthorizedRequest(actionContext);
            else
            {
                ClaimsIdentity claimsIdentity = HttpContext.Current.User.Identity as ClaimsIdentity;
                string _role = claimsIdentity.FindFirst(ClaimTypes.Role).Value;
                bool isAuthorize = Roles.Any(role => role == _role);

                if(!isAuthorize)
                    HandleUnauthorizedRequest(actionContext);
            }
        }

Et voilà, il valide maintenant si le rôle est autorisé à accéder à la ressource

1

J'ai l'impression qu'un attribut authorize personnalisé est excessif pour ce problème, sauf si vous avez une grande quantité de rôles.

Puisque la chaîne doit être connue au moment de la compilation, créez une classe de rôle statique contenant les chaînes publiques des rôles que vous avez définis, puis ajoutez des chaînes séparées par des virgules avec certains rôles que vous souhaitez autoriser: 

public static class Roles
{
    public const string ADMIN = "Admin";
    public const string VIEWER = "Viewer";

    public const string ADMIN_OR_VIEWER = ADMIN + "," + VIEWER;
}

Et vous pouvez ensuite utiliser l'attribut Authorize de la même manière sur la classe de contrôleur ou la méthode de contrôleur (ou les deux):

[Authorize(Roles = Roles.ADMIN]
public class ExampleController : Controller
{
    [Authorize(Roles = Roles.ADMIN_OR_VIEWER)
    public ActionResult Create()
    {
        ..code here...
    }
}
0
Robert Tuttle