Lectura de AuthorizationFilterContext en netcore api 3.1

9

Tengo un proyecto de trabajo en netcore 2.2 en el que he implementado una política personalizada que verifica las claves API.

En startup.cs estoy agregando esta política como esta

//Add Key Policy
services.AddAuthorization(options =>
{
    options.AddPolicy("AppKey", policy => policy.Requirements.Add(new AppKeyRequirement()));
});

En mi AppKeyRequirement, heredo de AuthorizationHandler y resuelvo las claves en las solicitudes entrantes como esta

protected override Task HandleRequirementAsync(AuthorizationHandlerContext authContext, AppKeyRequirement requirement)
{
    var authorizationFilterContext = (AuthorizationFilterContext)authContext.Resource;
    var query = authorizationFilterContext.HttpContext.Request.Query;

    if (query.ContainsKey("key") && query.ContainsKey("app"))
    { // Do stuff

Esto no funciona en netcore 3.1

Estoy teniendo el siguiente error:

No se puede emitir el objeto de tipo 'Microsoft.AspNetCore.Routing.RouteEndpoint' para escribir 'Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext'.

¿Cuál es la forma correcta de hacer esto en el núcleo 3 y superior?

Como señaló Kirk Larkin, la forma correcta en .net 3.0 y superior es inyectar IHttpContextAccessor en el controlador Auth y usarlo.

Mi pregunta en este momento es ¿cómo puedo inyectar esto? No puedo pasar esto en startup.cs o al menos no veo cómo.

Cualquier idea / pista será muy apreciada.

w2olves
fuente

Respuestas:

14

En versiones anteriores a ASP.NET Core 3.0, IAuthorizationHandlerse llamaron implementaciones de durante la canalización de MVC. En 3.0 en adelante, que usa enrutamiento de punto final (por defecto), estas implementaciones son llamadas por el middleware de autorización ( UseAuthorization()). Este middleware se ejecuta antes de la canalización MVC, y no como parte de él.

Este cambio significa que AuthorizationFilterContextya no se pasa a los manejadores de autorización. En cambio, es una instancia de RouteEndpoint, que no proporciona acceso a HttpContext.

En su ejemplo, solo está utilizando AuthorizationFilterContextpara hacerse con HttpContext. En 3.0+, inyecte IHttpContextAccessoren su controlador de autorización y úselo. Aquí hay un ejemplo de integridad:

public class AppKeyAuthorizationHandler : AuthorizationHandler<AppKeyRequirement>
{
    private readonly IHttpContextAccessor httpContextAccessor;

    public AppKeyAuthorizationHandler(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }

    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext authContext, AppKeyRequirement requirement)
    {
        var httpContext = httpContextAccessor.HttpContext;
        var query = httpContext.Request.Query;

        if (query.ContainsKey("key") && query.ContainsKey("app"))
        {
            // ...
        }
    }
}

Es posible que también deba registrarse IHttpContextAccessoren ConfigureServices:

services.AddHttpContextAccessor();

Consulte Usar HttpContext de componentes personalizados para obtener más información sobre el uso IHttpContextAccessor.

Kirk Larkin
fuente
1
Gracias por esta pista. Estoy tratando de crear una política donde, si falta una clave API, la llamada será rechazada. Ya no podemos usar // Agregar servicios de política clave. Agregar autorización (options => {options.AddPolicy ("AppKey", policy => policy.Requirements.Add (new AppKeyRequirement ()));}); Si no, ¿cómo puedo interceptar una llamada antes de que llegue a una acción del controlador?
w2olves
1
Sí, eso sigue funcionando igual que antes.
Kirk Larkin
El constructor espera IHttpContextAccessor, ¿cómo puedo pasar esto cuando creo la política en Startup.cs? services.AddAuthorization (options => {options.AddPolicy ("AppKey", policy => policy.Requirements.Add (new AppKeyRequirement ()));}); También puedo crear un nuevo constructor predeterminado para AppKeyAuthorizationHandler pero luego httpContextAccessor.HttpContext; es nulo cuando llega una solicitud. ¿Alguna idea?
w2olves
1
Agregue su controlador utilizando DI, que crea una instancia del mismo para usted y pasa el IHttpContextAccessor. Ver los documentos .
Kirk Larkin el