Estoy tratando de hacer un atributo de autorización personalizado en ASP.NET Core. En versiones anteriores era posible anular bool AuthorizeCore(HttpContextBase httpContext)
. Pero esto ya no existe en AuthorizeAttribute
.
¿Cuál es el enfoque actual para hacer un AuthorizeAttribute personalizado?
Lo que estoy tratando de lograr: estoy recibiendo una ID de sesión en la Autorización de encabezado. A partir de ese ID sabré si una acción en particular es válida.
Respuestas:
El enfoque recomendado por el equipo de ASP.Net Core es utilizar el nuevo diseño de política que está completamente documentado aquí . La idea básica detrás del nuevo enfoque es usar el nuevo atributo [Autorizar] para designar una "política" (por ejemplo,
[Authorize( Policy = "YouNeedToBe18ToDoThis")]
cuando la política se registra en Startup.cs de la aplicación para ejecutar algún bloque de código (es decir, asegurarse de que el usuario tenga un reclamo de antigüedad) donde la edad es 18 años o más).El diseño de la política es una gran adición al marco y el equipo de ASP.Net Security Core debe ser elogiado por su introducción. Dicho esto, no es adecuado para todos los casos. La desventaja de este enfoque es que no proporciona una solución conveniente para la necesidad más común de simplemente afirmar que un controlador o acción determinada requiere un tipo de reclamo dado. En el caso de que una aplicación pueda tener cientos de permisos discretos que rigen las operaciones CRUD en recursos REST individuales ("CanCreateOrder", "CanReadOrder", "CanUpdateOrder", "CanDeleteOrder", etc.), el nuevo enfoque requiere repetitivo de uno a otro una asignación entre un nombre de póliza y un nombre de reclamo (p. ej.
options.AddPolicy("CanUpdateOrder", policy => policy.RequireClaim(MyClaimTypes.Permission, "CanUpdateOrder));
), o escribir algún código para realizar estos registros en tiempo de ejecución (por ejemplo, leer todos los tipos de reclamo de una base de datos y realizar la llamada mencionada en un bucle). El problema con este enfoque para la mayoría de los casos es que es una sobrecarga innecesaria.Si bien el equipo de ASP.Net Core Security recomienda nunca crear su propia solución, en algunos casos esta puede ser la opción más prudente para comenzar.
La siguiente es una implementación que utiliza IAuthorizationFilter para proporcionar una manera simple de expresar un requisito de reclamo para un controlador o acción determinada:
fuente
new ForbidResult()
no funciona (causa una excepción / 500) porque no tiene un esquema de autorización asociado. ¿Qué usaría para este caso?Soy la persona de seguridad de asp.net.
En primer lugar, permítanme disculparme porque nada de esto está documentado aún fuera de la muestra de la tienda de música o de las pruebas unitarias, y todo se está refinando en términos de API expuestas.La documentación detallada está aquí .No queremos que escriba atributos de autorización personalizados. Si necesita hacer eso, hemos hecho algo mal. En cambio, debe escribir los requisitos de autorización .
La autorización actúa sobre las identidades. Las identidades se crean por autenticación.
Usted dice en los comentarios que desea verificar una ID de sesión en un encabezado. Su ID de sesión sería la base de la identidad. Si quisiera usar el
Authorize
atributo, escribiría un middleware de autenticación para tomar ese encabezado y convertirlo en un autenticadoClaimsPrincipal
. Luego verificaría eso dentro de un requisito de autorización. Los requisitos de autorización pueden ser tan complicados como desee, por ejemplo, aquí hay uno que toma una fecha de nacimiento de la identidad actual y autorizará si el usuario es mayor de 18 años;Luego, en su
ConfigureServices()
función, lo conectaríaY finalmente, aplíquelo a un controlador o método de acción con
fuente
ManageStore
requisito de la muestra de Music Store. Como está en la muestra, solo hay una forma de "permitir todo o nada" para hacerlo. ¿Entonces tenemos que crear una nueva política para cada permutación posible? es decir, "Usuarios / Leer", "Usuarios / Crear", "Usuarios / Asignar rol", "Usuarios / Eliminar" si queremos reclamos específicos. ¿Suena como un trabajo de configuración para que funcione y una gran cantidad de políticas solo para administrar reclamos en lugar de un[ClaimsAutzorization("User", "Read", "Create", "Delete", "Assign")]
atributo?[CustomAuthorize(Operator.And, Permission.GetUser, Permission.ModifyUser)]
. Podría usar un único atributo personalizado en infinitas formas simplemente modificando los parámetros del constructor.IAuthorizeData.Policy
) y proveedores de políticas personalizadas para superar esta evidente supervisión, en lugar de abordarla dentro del marco. ¿Pensé que no debíamos crear nuestras propias implementaciones? No nos ha dejado a varios más remedio que volver a implementar la autorización desde cero (nuevamente), y esta vez sin siquiera el beneficio del antiguoAuthorize
atributo de la API web . Ahora tenemos que hacerlo en el filtro de acción o en el nivel de middleware.Parece que con ASP.NET Core 2, puede volver a heredar
AuthorizeAttribute
, solo necesita implementarIAuthorizationFilter
(oIAsyncAuthorizationFilter
):fuente
OnAuthorization
implementación necesita esperar un método asíncrono, debe implementar enIAsyncAuthorizationFilter
lugar de loIAuthorizationFilter
contrario, su filtro se ejecutará sincrónicamente y su acción de controlador se ejecutará independientemente del resultado del filtro.Basado en la GRAN respuesta de Derek Greer , lo hice con enumeraciones.
Aquí hay un ejemplo de mi código:
fuente
Puede crear su propio AuthorizationHandler que encontrará atributos personalizados en sus Controladores y Acciones, y pasarlos al método HandleRequirementAsync.
Luego puede usarlo para cualquier atributo personalizado que necesite en sus controladores o acciones. Por ejemplo, para agregar requisitos de permisos. Simplemente cree su atributo personalizado.
Luego cree un Requisito para agregar a su Política
Luego cree el AuthorizationHandler para su atributo personalizado, heredando el AttributeAuthorizationHandler que creamos anteriormente. Se pasará un IEnumerable para todos sus atributos personalizados en el método HandleRequirementsAsync, acumulado desde su Controlador y Acción.
Y, por último, en su método Startup.cs ConfigureServices, agregue su AuthorizationHandler personalizado a los servicios y agregue su Política.
Ahora puede simplemente decorar sus Controladores y Acciones con su atributo personalizado.
fuente
Fácil: no cree el suyo propio
AuthorizeAttribute
.Para escenarios de autorización pura (como restringir el acceso solo a usuarios específicos), el enfoque recomendado es usar el nuevo bloque de autorización: https://github.com/aspnet/MusicStore/blob/1c0aeb08bb1ebd846726232226279bbe001782e1/samples/MusicStore/Startup.cs#L84 -L92
Para la autenticación, se maneja mejor en el nivel de middleware.
¿Qué estás tratando de lograr exactamente?
fuente
Si alguien solo quiere validar un token de portador en la fase de autorización utilizando las prácticas de seguridad actuales que puede,
agregue esto a su Startup / ConfigureServices
y esto en tu base de código,
Si el código no llega
context.Succeed(...)
, fallará de todos modos (401).Y luego en tus controladores puedes usar
fuente
La forma moderna es AuthenticationHandlers
en startup.cs agregar
IUserService es un servicio que realiza cuando tiene nombre de usuario y contraseña. básicamente, devuelve una clase de usuario que usa para asignar sus reclamos.
Luego puede consultar estos reclamos y cualquier dato que haya mapeado, hay bastantes, eche un vistazo a la clase ClaimTypes
puede usar esto en un método de extensión y obtener cualquiera de las asignaciones
Esta nueva forma, creo que es mejor que
fuente
Al momento de escribir este artículo, creo que esto se puede lograr con la interfaz IClaimsTransformation en asp.net core 2 y superior. Acabo de implementar una prueba de concepto que es lo suficientemente compartible para publicar aquí.
Para usar esto en su controlador, simplemente agregue un apropiado
[Authorize(Roles="whatever")]
a sus métodos.En nuestro caso, cada solicitud incluye un encabezado de autorización que es un JWT. Este es el prototipo y creo que haremos algo muy parecido a esto en nuestro sistema de producción la próxima semana.
Futuros votantes, consideren la fecha de escritura cuando voten. A partir de hoy, esto
works on my machine.
™ Probablemente desee más manejo de errores e inicio de sesión en su implementación.fuente
Para autorización en nuestra aplicación. Tuvimos que llamar a un servicio basado en los parámetros pasados en el atributo de autorización.
Por ejemplo, si queremos verificar si el médico registrado puede ver las citas de los pacientes, pasaremos "View_Appointment" para personalizar el atributo de autorización y lo verificaremos directamente en el servicio de base de datos y en función de los resultados que autorizaremos. Aquí está el código para este escenario:
Y en la acción API lo usamos así:
fuente
La respuesta aceptada ( https://stackoverflow.com/a/41348219/4974715 ) no es mantenible o adecuada de manera realista porque "CanReadResource" se está utilizando como un reclamo (pero esencialmente debería ser una política en realidad, IMO). El enfoque en la respuesta no está bien en la forma en que se usó, porque si un método de acción requiere muchas configuraciones de reclamos diferentes, entonces con esa respuesta tendría que escribir repetidamente algo como ...
Entonces, imagine la cantidad de codificación que tomaría. Idealmente, se supone que "CanReadResource" es una política que utiliza muchos reclamos para determinar si un usuario puede leer un recurso.
Lo que hago es crear mis políticas como una enumeración y luego recorrer y configurar los requisitos de esta manera ...
La clase DefaultAuthorizationRequirement se parece a ...
Tenga en cuenta que el código anterior también puede habilitar la asignación previa de un usuario a una política en su almacén de datos. Por lo tanto, al redactar reclamos para el usuario, básicamente recupera las políticas que se habían asignado previamente al usuario directa o indirectamente (por ejemplo, porque el usuario tiene un cierto valor de reclamo y ese valor de reclamo se ha identificado y asignado a una política, como que proporciona un mapeo automático para los usuarios que también tienen ese valor de reclamo), y alista las políticas como reclamos, de modo que en el controlador de autorización, simplemente puede verificar si los reclamos del usuario contienen requisitos. reclamación (es. Esto es para una forma estática de satisfacer un requisito de política, por ejemplo, el requisito de "nombre" es de naturaleza bastante estática. Entonces,
Un requisito dinámico puede ser verificar el rango de edad, etc. y las políticas que usan dichos requisitos no pueden asignarse previamente a los usuarios.
En la respuesta dada por @blowdart ( https://stackoverflow.com/a/31465227/4974715 ) ya se encuentra un ejemplo de verificación dinámica de reclamos de políticas (por ejemplo, para verificar si un usuario tiene más de 18 años ).
PD: escribí esto en mi teléfono. Disculpe cualquier error tipográfico y falta de formato.
fuente