J'ai un contrôleur et je veux que deux rôles puissent y accéder. 1-admin OR 2 modérateur
Je sais que vous pouvez faire [Autoriser (Roles = "admin, modérateurs")] mais j'ai mes rôles dans un enum. Avec l'énumération, je ne peux qu'autoriser UN rôle. Je n'arrive pas à comprendre comment en autoriser deux.
J'ai essayé quelque chose comme [Autoriser (Roles = MyEnum.Admin, MyEnum.Moderator)] mais cela ne compilera pas.
Quelqu'un a déjà suggéré ceci:
[Authorize(Roles=MyEnum.Admin)]
[Authorize(MyEnum.Moderator)]
public ActionResult myAction()
{
}
mais cela ne fonctionne pas comme un OU. Je pense que dans ce cas, l'utilisateur doit faire partie des DEUX rôles. Est-ce que je néglige une syntaxe? Ou est-ce un cas où je dois lancer ma propre autorisation personnalisée?
Essayez d’utiliser l’opérateur bit OR comme ceci:
[Authorize(Roles= MyEnum.Admin | MyEnum.Moderator)]
public ActionResult myAction()
{
}
Si cela ne fonctionne pas, vous pouvez simplement rouler le vôtre. Je viens juste de faire cela sur mon projet. Voici ce que j'ai fait:
public class AuthWhereRole : AuthorizeAttribute
{
/// <summary>
/// Add the allowed roles to this property.
/// </summary>
public UserRole Is;
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
// Make sure the user is authenticated.
if (!httpContext.User.Identity.IsAuthenticated)
return false;
UserRole role = someUser.Role; // Load the user's role here
// Perform a bitwise operation to see if the user's role
// is in the passed in role values.
if (Is != 0 && ((Is & role) != role))
return false;
return true;
}
}
// Example Use
[AuthWhereRole(Is=MyEnum.Admin|MyEnum.Newbie)]
public ActionResult Test() {}
En outre, assurez-vous d’ajouter un attribut flags à votre enum et assurez-vous qu’ils ont tous la valeur 1 et plus. Comme ça:
[Flags]
public enum Roles
{
Admin = 1,
Moderator = 1 << 1,
Newbie = 1 << 2
etc...
}
Le décalage de bit de gauche donne les valeurs 1, 2, 4, 8, 16 et ainsi de suite.
Eh bien, j'espère que cela aide un peu.
Voici une solution simple et élégante qui vous permet d'utiliser simplement la syntaxe suivante:
[AuthorizeRoles(MyEnum.Admin, MyEnum.Moderator)]
Lorsque vous créez votre propre attribut, utilisez le mot cléparams
dans votre constructeur:
public class AuthorizeRoles : AuthorizeAttribute
{
public AuthorizeRoles(params MyEnum[] roles)
{
...
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
...
}
}
Cela vous permettra d'utiliser l'attribut comme suit:
[AuthorizeRoles(MyEnum.Admin, MyEnum.Moderator)]
public ActionResult myAction()
{
}
J'ai combiné quelques-unes des solutions ici pour créer mon préféré. Mon attribut personnalisé modifie simplement les données afin qu'elles se présentent sous la forme attendue par SimpleMembership et lui permettent de gérer tout le reste.
Mes rôles enum:
public enum MyRoles
{
Admin,
User,
}
Pour créer des rôles:
public static void CreateDefaultRoles()
{
foreach (var role in Enum.GetNames(typeof(MyRoles)))
{
if (!Roles.RoleExists(role))
{
Roles.CreateRole(role);
}
}
}
Attribut personnalisé:
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
public AuthorizeRolesAttribute(params MyRoles[] allowedRoles)
{
var allowedRolesAsStrings = allowedRoles.Select(x => Enum.GetName(typeof(MyRoles), x));
Roles = string.Join(",", allowedRolesAsStrings);
}
}
Utilisé comme tel:
[AuthorizeRoles(MyRoles.Admin, MyRoles.User)]
public ActionResult MyAction()
{
return View();
}
Essayer
public class CustomAuthorize : AuthorizeAttribute
{
public enum Role
{
DomainName_My_Group_Name,
DomainName_My_Other_Group_Name
}
public CustomAuthorize(params Role[] DomainRoles)
{
foreach (var domainRole in DomainRoles)
{
var domain = domainRole.ToString().Split('_')[0] + "_";
var role = domainRole.ToString().Replace(domain, "").Replace("_", " ");
domain=domain.Replace("_", "\\");
Roles += ", " + domain + role;
}
Roles = Roles.Substring(2);
}
}
public class HomeController : Controller
{
[CustomAuthorize(Role.DomainName_My_Group_Name, Role.DomainName_My_Other_Group_Name)]
public ActionResult Index()
{
return View();
}
}
Voici ma version, basée sur les réponses de @CalebHC et de @Lee Harold.
J'ai suivi le style d'utilisation des paramètres nommés dans l'attribut et remplacé la propriété Roles
des classes de base.
La réponse de @ CalebHC utilise une nouvelle propriété Is
qui, à mon avis, est inutile, car AuthorizeCore()
est surchargé (qui dans la classe de base utilise des rôles), il est donc logique d'utiliser également notre propre variable Roles
. En utilisant notre propre variable Roles
, nous pouvons écrire Roles = Roles.Admin
sur le contrôleur, qui suit le style des autres attributs .Net.
J'ai utilisé deux constructeurs pour CustomAuthorizeAttribute
pour montrer les vrais noms de groupe Active Directory passés. En production, j'utilise le constructeur paramétré pour éviter les chaînes magiques de la classe: les noms de groupe sont extraits de web.config lors de Application_Start()
et transmis lors de la création à l'aide de un outil de DI.
Vous aurez besoin d'un NotAuthorized.cshtml
ou similaire dans votre dossier Views\Shared
, sinon les utilisateurs non autorisés obtiendront un message d'erreur.
Voici le code de la classe de base AuthorizationAttribute.cs .
Manette:
public ActionResult Index()
{
return this.View();
}
[CustomAuthorize(Roles = Roles.Admin)]
public ActionResult About()
{
return this.View();
}
CustomAuthorizeAttribute:
// The left bit shifting gives the values 1, 2, 4, 8, 16 and so on.
[Flags]
public enum Roles
{
Admin = 1,
User = 1 << 1
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
private readonly string adminGroupName;
private readonly string userGroupName;
public CustomAuthorizeAttribute() : this("Domain Admins", "Domain Users")
{
}
private CustomAuthorizeAttribute(string adminGroupName, string userGroupName)
{
this.adminGroupName = adminGroupName;
this.userGroupName = userGroupName;
}
/// <summary>
/// Gets or sets the allowed roles.
/// </summary>
public new Roles Roles { get; set; }
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext">The HTTP context.</param>
/// <returns>[True] if the user is authenticated and has the correct role</returns>
/// <remarks>
/// This method must be thread-safe since it is called by the thread-safe OnCacheAuthorization() method.
/// </remarks>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
if (!httpContext.User.Identity.IsAuthenticated)
{
return false;
}
var usersRoles = this.GetUsersRoles(httpContext.User);
return this.Roles == 0 || usersRoles.Any(role => (this.Roles & role) == role);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
filterContext.Result = new ViewResult { ViewName = "NotAuthorized" };
}
private IEnumerable<Roles> GetUsersRoles(IPrincipal principal)
{
var roles = new List<Roles>();
if (principal.IsInRole(this.adminGroupName))
{
roles.Add(Roles.Admin);
}
if (principal.IsInRole(this.userGroupName))
{
roles.Add(Roles.User);
}
return roles;
}
}
Pour ajouter au code de CalebHC et répondre à la question de ssmith sur la gestion des utilisateurs ayant plusieurs rôles ...
Notre entité de sécurité personnalisée renvoie un tableau de chaînes représentant tous les groupes/rôles dans lesquels se trouve un utilisateur. Nous devons donc d'abord convertir toutes les chaînes du tableau qui correspondent aux éléments de l'énumération. Enfin, nous recherchons une correspondance - si c'est le cas, l'utilisateur est autorisé.
Notez que nous redirigeons également un utilisateur non autorisé vers une vue "NotAuthorized" personnalisée.
Toute la classe ressemble à ceci:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
/// <summary>
/// Add the allowed roles to this property.
/// </summary>
public Roles Is { get; set; }
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
if (!httpContext.User.Identity.IsAuthenticated)
return false;
var iCustomPrincipal = (ICustomPrincipal) httpContext.User;
var roles = iCustomPrincipal.CustomIdentity
.GetGroups()
.Select(s => Enum.Parse(typeof (Roles), s))
.ToArray();
if (Is != 0 && !roles.Cast<Roles>().Any(role => ((Is & role) == role)))
{
return false;
}
return true;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
filterContext.Result = new ViewResult { ViewName = "NotAuthorized" };
}
}