Autorización simple en ASP.NET Core

La autorización en ASP.NET Core se controla con AuthorizeAttribute y sus diversos parámetros. En su forma más básica, aplicar el atributo [Authorize] a un controlador, una acción o una Razor Page limita el acceso a ese componente para los usuarios autenticados.

El código siguiente limita el acceso al AccountController a los usuarios autenticados:

[Authorize]
public class AccountController : Controller
{
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

Si desea aplicar autorización a una acción en lugar del controlador, aplique el atributo AuthorizeAttribute a la propia acción:

public class AccountController : Controller
{
   public ActionResult Login()
   {
   }

   [Authorize]
   public ActionResult Logout()
   {
   }
}

Ahora solo los usuarios autenticados pueden acceder a la función Logout.

También puede usar el atributo AllowAnonymous para permitir el acceso de los usuarios no autenticados a acciones individuales. Por ejemplo:

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

Esto solo permitiría a los usuarios autenticados en AccountController, excepto para la acción Login, a la que todos pueden acceder, independientemente de su estado autenticado o no autenticado o anónimo.

Advertencia

[AllowAnonymous] omite las instrucciones de autorización. Si combina [AllowAnonymous] y un atributo [Authorize], se omiten los atributos [Authorize]. Por ejemplo, si se aplica [AllowAnonymous] en el nivel de controlador:

  • Se omiten los requisitos de autorización de los atributos [Authorize] en los mismos métodos de controlador o acción del controlador.
  • El middleware de autenticación no está cortocircuitado, pero no es necesario que se realice correctamente.

El código siguiente limita el acceso a la LogoutModel de Razor Page para los usuarios autenticados:

[Authorize]
public class LogoutModel : PageModel
{
    public async Task OnGetAsync()
    {

    }

    public async Task<IActionResult> OnPostAsync()
    {

    }
}

Para obtener información sobre cómo requerir globalmente la autenticación de todos los usuarios, vea Requerir usuarios autenticados.

Autorización de atributo y Razor Pages

El AuthorizeAttributeno se puede aplicar a los controladores de Razor Page. Por ejemplo, [Authorize] no se puede aplicar a OnGet, OnPost, ni a ningún otro controlador de páginas. Considere la posibilidad de usar un controlador MVC de ASP.NET Core para páginas con requisitos de autorización diferentes para diferentes controladores. El uso de un controlador MVC cuando se requieren requisitos de autorización diferentes:

  • Es el enfoque menos complejo.
  • Es el enfoque recomendado por Microsoft.

Si decide no usar un controlador MVC, se pueden usar los dos enfoques siguientes para aplicar la autorización a los métodos de controlador de Razor Pages:

  • Use páginas independientes para los controladores de página que requieren una autorización diferente. Mueva el contenido compartido a una o varias vistas parciales. Cuando sea posible, este es el enfoque recomendado.

  • Para el contenido que debe compartir una página común, escriba un filtro que realice la autorización como parte de IAsyncPageFilter.OnPageHandlerSelectionAsync. El proyecto de GitHub PageHandlerAuth muestra este enfoque:

    [TypeFilter(typeof(AuthorizeIndexPageHandlerFilter))]
    public class IndexModel : PageModel
    {
        private readonly ILogger<IndexModel> _logger;
    
        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }
    
        public void OnGet()
        {
    
        }
    
        public void OnPost()
        {
    
        }
    
        [AuthorizePageHandler]
        public void OnPostAuthorized()
        {
    
        }
    }
    
    public class AuthorizeIndexPageHandlerFilter : IAsyncPageFilter, IOrderedFilter
    {
        private readonly IAuthorizationPolicyProvider policyProvider;
        private readonly IPolicyEvaluator policyEvaluator;
    
        public AuthorizeIndexPageHandlerFilter(
            IAuthorizationPolicyProvider policyProvider,
            IPolicyEvaluator policyEvaluator)
        {
            this.policyProvider = policyProvider;
            this.policyEvaluator = policyEvaluator;
        }
    
        // Run late in the selection pipeline
        public int Order => 10000;
    
        public Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) => next();
    
        public async Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
        {
            var attribute = context.HandlerMethod?.MethodInfo?.GetCustomAttribute<AuthorizePageHandlerAttribute>();
            if (attribute is null)
            {
                return;
            }
    
            var policy = await AuthorizationPolicy.CombineAsync(policyProvider, new[] { attribute });
            if (policy is null)
            {
                return;
            }
    
            await AuthorizeAsync(context, policy);
        }
    
        #region AuthZ - do not change
        private async Task AuthorizeAsync(ActionContext actionContext, AuthorizationPolicy policy)
        {
            var httpContext = actionContext.HttpContext;
            var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, httpContext);
            var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, httpContext, actionContext.ActionDescriptor);
            if (authorizeResult.Challenged)
            {
                if (policy.AuthenticationSchemes.Count > 0)
                {
                    foreach (var scheme in policy.AuthenticationSchemes)
                    {
                        await httpContext.ChallengeAsync(scheme);
                    }
                }
                else
                {
                    await httpContext.ChallengeAsync();
                }
    
                return;
            }
            else if (authorizeResult.Forbidden)
            {
                if (policy.AuthenticationSchemes.Count > 0)
                {
                    foreach (var scheme in policy.AuthenticationSchemes)
                    {
                        await httpContext.ForbidAsync(scheme);
                    }
                }
                else
                {
                    await httpContext.ForbidAsync();
                }
    
                return;
            }
        }
    

Advertencia

El enfoque de ejemplo PageHandlerAuthno:

  • Crea con atributos de autorización aplicados a la página, el modelo de página o globalmente. La redacción de atributos de autorización da como resultado la autenticación y autorización que se ejecuta varias veces cuando también se aplican una o varias instancias AuthorizeAttribute o AuthorizeFilter a la página.
  • Trabaje junto con el resto del sistema de autenticación y autorización de ASP.NET Core. Debe comprobar que el uso de este enfoque funciona correctamente para la aplicación.

No hay planes para admitir AuthorizeAttribute en los controladores de Razor Page.