GOOGLE ADS

domingo, 1 de mayo de 2022

Cómo escribir un controlador de políticas asíncrono, inyectando un servicio con ámbito

Estoy tratando de escribir una política personalizada para una aplicación web ASP.NET Core 3.1, usando un proveedor de almacenamiento de identidad personalizado.

Traté de entender el hecho de que las políticas en ASP.NET Core están diseñadas para tomar información del usuario de un HttpContextobjeto, cuando leí esto en un artículo de MSDN:

una vez que tenga una referencia al usuario, siempre puede encontrar el nombre de usuario de los reclamos y ejecutar una consulta en cualquier base de datos o servicio externo

Empecé a escribir mi propia política (a partir de ahora un simple requisito de rol) inyectando UserManageren el constructor:

public class RoleHandler: AuthorizationHandler<RoleRequirement>
{
private UserManager<AppUser> UserManager;
public RoleHandler(UserManager<AppUser> usermanager)
{
UserManager = usermanager;
}
}

Ahora tengo un par de problemas:

INYECTAR UN SERVICIO CON ALCANCE EN UN SOLOTON

Se supone que las políticas duran toda la vida de la aplicación, por lo que sería un Singleton:

services.AddSingleton<IAuthorizationHandler, RoleHandler>();

pero el UserManager inyectado en el servidor de políticas es un servicio de alcance y eso no está permitido. La solución fue muy fácil, cambiando la configuración del servicio de políticas de un servicio único a un servicio con ámbito

services.AddScoped<IAuthorizationHandler, RoleHandler>();

pero no sé si eso causa algún problema o no.

ESCRIBIR UN MANEJADOR DE POLÍTICAS ASINCRÓNICO

Esta es mi implementación del HandleRequirementAsyncmétodo:

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
AppUser user = UserManager.FindByIdAsync(context.User.Identity.Name).Result;
if (user!= null)
{
bool result = UserManager.IsInRoleAsync(user, requirement.Role.ToString()).Result;
if (result) context.Succeed(requirement);
}
return Task.CompletedTask;
}

Lo usé Task.Resultpero bloquea el hilo. No puedo usar awaitporque eso haría que el método devolviera a en Task<Task>lugar de a Tasky no puedo cambiarlo. ¿Como puedo resolver esto?


Solución del problema

no Task.CompletedTaskregreses

Cuando declara un método como async, implícitamente devuelve un Taskcuando awaitse golpea el primero:

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
AppUser user = await UserManager.FindByIdAsync(context.User.Identity.Name);
if (user!= null)
{
bool result = await UserManager.IsInRoleAsync(user, requirement.Role.ToString());
if (result) context.Succeed(requirement);
}
}

Task.CompletedTaskgeneralmente se usa cuando necesita implementar un Taskmétodo de devolución de forma sincrónica, lo cual no es así.

No hay comentarios:

Publicar un comentario

Regla de Firestore para acceder a la generación de subcolección Permisos faltantes o insuficientes

Tengo problemas con las reglas de Firestore para permitir el acceso a algunos recursos en una subcolección. Tengo algunos requests document...