2009-03-31 21 views
176

En ce moment, je décore une méthode comme celui-ci pour permettre à « membres » d'accéder à mon action du contrôleurAutoriser plusieurs rôles d'accéder à l'action du contrôleur

[Authorize(Roles="members")] 

Comment puis-je permettre à plus d'un rôle? Par exemple, le suivant ne fonctionne pas, mais il montre ce que je suis en train de faire (permettre aux « membres » et « admin » accès):

[Authorize(Roles="members", "admin")] 
+4

Veuillez modifier la réponse acceptée à cette question. La personne avec la réponse actuellement acceptée l'a éditée en indiquant qu'il avait tort. –

Répondre

467

Une autre option est d'utiliser un seul filtre authorize que vous avez publié, mais retirer les citations intérieures.

[Authorize(Roles="members, admin")] 
+3

Fonctionne dans MVC3 et MVC4 +1 –

+4

Fonctionne également dans MVC 5. +1 – gkon

+4

Fonctionne dans ASP.NET Core 1.0 (MVC 6) et Microsoft.AspNet.Identity v3. * – Soren

91

Si vous voulez utiliser des rôles personnalisés, vous pouvez le faire:

CustomRoles Classe:

public static class CustomRoles 
{ 
    public const string Administrator = "Administrador"; 
    public const string User = "Usuario"; 
} 

Utilisation

[Authorize(Roles = CustomRoles.Administrator +","+ CustomRoles.User)] 

Si vous avez quelques rôles, vous pouvez peut-être combinez-les (pour plus de clarté) comme ceci:

public static class CustomRoles 
{ 
    public const string Administrator = "Administrador"; 
    public const string User = "Usuario"; 
    public const string AdministratorOrUser = Administrator + "," + User; 
} 

Utilisation

[Authorize(Roles = CustomRoles.AdministratorOrUser)] 
+5

Ce serait une bonne réponse si vous expliquiez à des personnes qui ne savaient pas ce qui se cache derrière CustomRoles. –

+1

@ JamesSkemp ok, j'ai prolongé ma réponse. C'est très simple. CustumRoles est une classe que j'ai créée qui contient des constantes, qui correspondent à mes rôles d'application. Je l'ai fait pour quelques raisons: 1) Il permet l'utilisation d'intellisense pour éviter les fautes d'orthographe 2) Pour simplifier la maintenance. Si un changement de rôle, je dois mettre à jour seulement un endroit dans mon application. –

+0

@Pabloker Vous pouvez également créer une énumération avec un attribut Flags, par exemple. Convert.ToString (CustomRoles.Administrator | CustomRoles.User); - la partie ennuyante est que ceci exige une conversion explicite. – cstruter

14

Pour MVC4, en utilisant un Enum (UserRoles) avec mes rôles, j'utilise une coutume AuthorizeAttribute.

Sur mon action contrôlée, je fais:

[CustomAuthorize(UserRoles.Admin, UserRoles.User)] 
public ActionResult ChangePassword() 
{ 
    return View(); 
} 

Et j'utilise une coutume AuthorizeAttribute comme ça:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 
public class CustomAuthorize : AuthorizeAttribute 
{ 
    private string[] UserProfilesRequired { get; set; } 

    public CustomAuthorize(params object[] userProfilesRequired) 
    { 
     if (userProfilesRequired.Any(p => p.GetType().BaseType != typeof(Enum))) 
      throw new ArgumentException("userProfilesRequired"); 

     this.UserProfilesRequired = userProfilesRequired.Select(p => Enum.GetName(p.GetType(), p)).ToArray(); 
    } 

    public override void OnAuthorization(AuthorizationContext context) 
    { 
     bool authorized = false; 

     foreach (var role in this.UserProfilesRequired) 
      if (HttpContext.Current.User.IsInRole(role)) 
      { 
       authorized = true; 
       break; 
      } 

     if (!authorized) 
     { 
      var url = new UrlHelper(context.RequestContext); 
      var logonUrl = url.Action("Http", "Error", new { Id = 401, Area = "" }); 
      context.Result = new RedirectResult(logonUrl); 

      return; 
     } 
    } 
} 

Cela fait partie de modifed FNHMVC par Fabricio Martínez Tamayo https://github.com/fabriciomrtnz/FNHMVC/

+1

Votre méthode OnAuthorization exigera que l'utilisateur ait ** tous ** les rôles énumérés; était-ce intentionnel, ou manquez-vous une pause dans cette boucle? –

+0

@Tieson: J'ai inspecté cela de très près, il semble définitivement qu'une pause serait nécessaire dans cette boucle. – OcelotXL

+0

@TiesonT. et @ madrush, j'apprécie votre solution, il pourrait vraiment faire une pause dans la boucle. Je vais changer le code ci-dessus. –

57

Une simplification possible serait de sous-classe AuthorizeAttribute:

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

Utilisation:

[Roles("members", "admin")] 

sémantiquement il est le même que la réponse de Jim Schmehil.

+1

Cela ne fonctionne pas pour moi, l'utilisateur connecté a été en mesure de contourner l'attribut même si l'utilisateur n'avait aucun des rôles. – Urielzen

+2

Cette réponse est préférable lorsque vous utilisez des constantes comme valeurs: ie [Roles (Constants.Admin, Constants.Owner)] – user1191559

0

Code mieux avec l'ajout d'une sous-classe AuthorizeRole.cs

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 
    class AuthorizeRoleAttribute : AuthorizeAttribute 
    { 
     public AuthorizeRoleAttribute(params Rolenames[] roles) 
     { 
      this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r))); 
     } 
     protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext) 
     { 
      if (filterContext.HttpContext.Request.IsAuthenticated) 
      { 
       filterContext.Result = new RedirectToRouteResult(
       new RouteValueDictionary { 
        { "action", "Unauthorized" }, 
        { "controller", "Home" }, 
        { "area", "" } 
        } 
      ); 
       //base.HandleUnauthorizedRequest(filterContext); 
      } 
      else 
      { 
       filterContext.Result = new RedirectToRouteResult(
       new RouteValueDictionary { 
        { "action", "Login" }, 
        { "controller", "Account" }, 
        { "area", "" }, 
        { "returnUrl", HttpContext.Current.Request.Url } 
        } 
      ); 
      } 
     } 
    } 

Comment utiliser ce

[AuthorizeRole(Rolenames.Admin,Rolenames.Member)] 

public ActionResult Index() 
{ 
return View(); 
} 
1

Une autre solution claire, vous pouvez utiliser des constantes pour maintenir la convention et ajouter plusieurs attributs [Authorize].Check this out:

public static class RolesConvention 
{ 
    public const string Administrator = "Administrator"; 
    public const string Guest = "Guest"; 
} 

Ensuite, dans le contrôleur:

[Authorize(Roles = RolesConvention.Administrator)] 
[Authorize(Roles = RolesConvention.Guest)] 
[Produces("application/json")] 
[Route("api/[controller]")] 
public class MyController : Controller 
+6

Plusieurs attributs 'Authorize' utilisent AND sémantique et nécessitent que TOUTES les conditions soient remplies (ie l'utilisateur doit être dans les rôles Administrateur et Invité). – trousyt

0

Si vous vous appliquer ces 2 rôles que vous pouvez souvent les envelopper trouvent dans leur propre Autorisez. C'est vraiment une extension de la réponse acceptée.

using System.Web.Mvc; 

public class AuthorizeAdminOrMember : AuthorizeAttribute 
{ 
    public AuthorizeAdminOrMember() 
    { 
     Roles = "members, admin"; 
    } 
} 

Ensuite, appliquez votre nouvelle autorisation à l'action. Je pense que cela semble plus propre et se lit facilement.

public class MyController : Controller 
{ 
    [AuthorizeAdminOrMember] 
    public ActionResult MyAction() 
    { 
     return null; 
    } 
}