Saltar al contenido

¿Cómo se crea un AuthorizeAttribute personalizado en ASP.NET Core?

Posteriormente a investigar en diferentes repositorios y sitios de internet al final hemos descubierto la solución que te mostramos a continuación.

Solución:

El enfoque recomendado por el equipo de ASP.Net Core es usar el nuevo diseño de política que se documenta completamente aquí. La idea básica detrás del nuevo enfoque es utilizar el nuevo [Authorize] attribute para designar una “política” (p. ej. [Authorize( Policy = "YouNeedToBe18ToDoThis")] donde la política está registrada 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 edad donde la edad sea mayor de 18 años).

El diseño de la política es una gran adición al marco y se debe elogiar al equipo de ASP.Net Security Core por su introducción. Dicho esto, no es adecuado para todos los casos. La deficiencia 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 una acción determinados requieren un tipo de notificación determinado. 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 repeticiones uno a una correspondencia entre un nombre de póliza y un nombre de reclamación (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 reclamos de una base de datos y realizar la llamada antes 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 forma sencilla de expresar un requisito de notificación para un controlador o una acción determinados:

public class ClaimRequirementAttribute : TypeFilterAttribute

    public ClaimRequirementAttribute(string claimType, string claimValue) : base(typeof(ClaimRequirementFilter))
    
        Arguments = new object[] new Claim(claimType, claimValue) ;
    


public class ClaimRequirementFilter : IAuthorizationFilter

    readonly Claim _claim;

    public ClaimRequirementFilter(Claim claim)
    
        _claim = claim;
    

    public void OnAuthorization(AuthorizationFilterContext context)
    
        var hasClaim = context.HttpContext.User.Claims.Any(c => c.Type == _claim.Type && c.Value == _claim.Value);
        if (!hasClaim)
        
            context.Result = new ForbidResult();
        
    



[Route("api/resource")]
public class MyController : Controller

    [ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
    [HttpGet]
    public IActionResult GetResource()
    
        return Ok();
    

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 las pruebas unitarias, y todo aún se está refinando en términos de API expuestas. La documentación detallada está aquí.

No queremos que escriba autorización personalizada attributes. Si necesitas hacer eso, hemos hecho algo mal. En su lugar, debe escribir una autorización requisitos.

La autorización actúa sobre las Identidades. Las identidades se crean mediante 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 para la identidad. Si desea utilizar el Authorize attribute escribiría un middleware de autenticación para tomar ese encabezado y convertirlo en un autenticado ClaimsPrincipal. 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 un reclamo de fecha de nacimiento en la identidad actual y autorizará si el usuario es mayor de 18 años;

public class Over18Requirement : AuthorizationHandler, IAuthorizationRequirement

        public override void Handle(AuthorizationHandlerContext context, Over18Requirement requirement)
        
            if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth))
            
                context.Fail();
                return;
            

            var dateOfBirth = Convert.ToDateTime(context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value);
            int age = DateTime.Today.Year - dateOfBirth.Year;
            if (dateOfBirth > DateTime.Today.AddYears(-age))
            
                age--;
            

            if (age >= 18)
            
                context.Succeed(requirement);
            
            else
            
                context.Fail();
            
        
    
}

Entonces en tu ConfigureServices() función que conectarías

services.AddAuthorization(options =>

    options.AddPolicy("Over18", 
        policy => policy.Requirements.Add(new Authorization.Over18Requirement()));
);

Y finalmente, aplicarlo a un controlador o método de acción con

[Authorize(Policy = "Over18")]

Parece que con ASP.NET Core 2, puede volver a heredar AuthorizeAttributesolo necesitas implementar también IAuthorizationFilter (o IAsyncAuthorizationFilter):

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter

    private readonly string _someFilterParameter;

    public CustomAuthorizeAttribute(string someFilterParameter)
    
        _someFilterParameter = someFilterParameter;
    

    public void OnAuthorization(AuthorizationFilterContext context)
    
        var user = context.HttpContext.User;

        if (!user.Identity.IsAuthenticated)
        
            // it isn't needed to set unauthorized result 
            // as the base class already requires the user to be authenticated
            // this also makes redirect to a login page work properly
            // context.Result = new UnauthorizedResult();
            return;
        

        // you can also use registered services
        var someService = context.HttpContext.RequestServices.GetService();

        var isAuthorized = someService.IsUserAuthorized(user.Identity.Name, _someFilterParameter);
        if (!isAuthorized)
        
            context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
            return;
        
    

Agradecemos que quieras estimular nuestro análisis fijando un comentario y dejando una valoración te damos las gracias.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *