Autorizar atributo con múltiples roles
Frecuentes
Visto 103,249 equipos
112
Me gustaría agregar Autorización a un controlador, para múltiples Roles a la vez.
Normalmente, eso se vería así:
[Authorize(Roles = "RoleA,RoleB,RoleC")]
public async Task<ActionResult> Index()
{
}
Pero he guardado mis Roles en constantes, ya que pueden cambiar o extenderse en algún momento.
public const RoleA = "RoleA";
public const RoleB = "RoleB";
public const RoleC = "RoleC";
No puedo hacer esto, ya que la cadena debe conocerse en tiempo de compilación:
[Authorize(Roles = string.join(",",RoleA,RoleB,RoleC)]
public async Task<ActionResult> Index()
{
}
¿Hay alguna manera de eludir el problema?
PODRÍA escribir una const que simplemente contenga "RoleA,RoleB,RoleC", pero no me gustan las cadenas mágicas y esta es una cadena mágica. Cambiar el nombre de un Rol y olvidarse de cambiar la cadena combinada sería un desastre.
Estoy usando MVC5. La identidad y el rol de ASP.NET se conocen en tiempo de compilación.
5 Respuestas
224
Intente crear un atributo de autorización personalizado como así.
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
public AuthorizeRolesAttribute(params string[] roles) : base()
{
Roles = string.Join(",", roles);
}
}
Suponiendo que sus funciones serán las mismas para varios controladores, cree una clase auxiliar:
public static class Role
{
public const string Administrator = "Administrator";
public const string Assistant = "Assistant";
}
Entonces úsalo así:
public class MyController : Controller
{
[AuthorizeRoles(Role.Administrator, Role.Assistant)]
public ActionResult AdminOrAssistant()
{
return View();
}
}
Respondido el 05 de enero de 15 a las 05:01
Esa es una idea digna de Mac Gyver ;) - cristian sauer
También me gusta mucho esta solución, especialmente porque puedo dejar que mi Rol sea una enumeración en lugar de una cadena. ¿Cuál sería un buen espacio de nombres y ubicación en la jerarquía del proyecto para colocar este atributo de autorización personalizado? - brillar
@SimonShine: creo que debería colocarlo en el proyecto web, por ejemplo, en la carpeta Atributos. Sin embargo, si tiene varios proyectos en una solución, deberá mover esto a otra biblioteca visible para cada proyecto. - MacGyver
No estoy seguro de lo que está pasando aquí, pero esto NO me ayudó, cualquier usuario, independientemente del rol, pudo acceder al método. - Urielzen
El mismo problema que @Urielzen, pero fue solucionado por la respuesta a continuación de Jerry Finegan (usando "System.Web.Mvc.AuthorizeAttribute y NO System.Web.Http.AuthorizeAttribute") - RJB
19
La forma mejor y más sencilla que encontré para resolver este problema es simplemente concatenar roles en el atributo Autorizar.
[Authorize(Roles = CustomRoles.Admin + "," + CustomRoles.OtherRole)]
con CustomRole una clase con cadenas constantes como esta:
public static class CustomRoles
{
public const string Admin = "Admin";
// and so on..
}
Respondido 31 Oct 18, 20:10
valioso; pero esto debería ser un comentario; no una respuesta - gato fantasma
Tanto su respuesta como la respuesta aceptada activarán la autorización si se implementan correctamente (estoy usando la aceptada en una aplicación web de producción). Proponer una edición para eliminar los comentarios sobre la respuesta aceptada. - Eric Eskildsen
Si los roles fueran enumeraciones, puede usar algo como [Authorize(Roles = nameof(UserRoleEnum.User) + "," + nameof(UserRoleEnum.Admin))] - Varun
14
Asegúrese de derivar su clase de atributo personalizado System.Web.Mvc.AuthorizeAttribute
y no System.Web.Http.AuthorizeAttribute
.
Tuve el mismo problema. Una vez que lo cambié, todo funcionó.
También es posible que desee agregar lo siguiente a su clase de atributo personalizado:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
Respondido 07 ago 16, 05:08
Acabo de probar esto y encontré una referencia a la biblioteca. System.Web.Http.AuthorizeAttribute
EN LUGAR DE System.Web.Mvc.AuthorizeAttribute
- fraser jordan
4
Lo que hice es la respuesta en @Tieson
Modifico un poco su respuesta. En lugar de cadena. Únase, ¿por qué no convertirlo en lista?
Esta es mi respuesta:
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
private new List<string> Roles;
public AuthorizeRolesAttribute(params string[] roles) : base()
{
Roles = roles.toList()
}
}
Y luego verifique si el rol es válido anulando 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);
}
}
Y ahí lo tienes, ahora está validando si el rol está autorizado para acceder al recurso.
respondido 08 mar '18, 01:03
2
Siento que un atributo de autorización personalizado es excesivo para este problema a menos que tenga una gran cantidad de roles.
Dado que la cadena debe conocerse en el momento de la compilación, ¿por qué no crear una clase de función estática que contenga cadenas públicas de las funciones que ha definido y luego agregar cadenas separadas por comas con ciertas funciones que desee autorizar?
public static class Roles
{
public const string ADMIN = "Admin";
public const string VIEWER = "Viewer";
public const string ADMIN_OR_VIEWER = ADMIN + "," + VIEWER;
}
Y luego puede usar el Atributo de autorización como tal en la Clase de controlador o el Método de controlador (o ambos):
[Authorize(Roles = Roles.ADMIN]
public class ExampleController : Controller
{
[Authorize(Roles = Roles.ADMIN_OR_VIEWER)
public ActionResult Create()
{
..code here...
}
}
Respondido 12 ago 17, 22:08
Este ejemplo no funciona, o al menos no de la manera que podrías pensar. Por ejemplo, mientras que la novela el ADMIN_OR_VIEWER
papel en la acción es redundante porque no se le permitirá llegar a la Create
método si aún no tiene el ADMIN
role. En este caso VIEWER
nunca podrá invocar Create
método. - Juan Leidegren
Esta solución tampoco es escalable. Habrá un punto en el que tengas demasiados roles con diferentes acciones y no deberías crear todas las combinaciones: edulopez
@JohnLeidegren esto es incorrecto. El AuthorizeAttribute de nivel de acción anula el AuthorizeAttribute de nivel de controlador, de lo contrario, no podría tener acciones decoradas con AllowAnonymousAttribute en un controlador con un AuthorizeAttribute - Tom pelusa
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c# asp.net-mvc authorization or haz tu propia pregunta.
¿está utilizando public const string RoleA = "RoleA"; o como has escrito en cuestión? - Mukesh Modhvadiya
posible duplicado de permitir que múltiples roles accedan a la acción del controlador - Ryan Kohn