Anular el atributo de autorización en ASP.NET MVC

83

Tengo una clase base de controlador MVC en la que apliqué el atributo Authorize ya que quiero que casi todos los controladores (y sus acciones) estén autorizados.

Sin embargo, necesito tener un controlador y una acción de otro controlador no autorizado. Quería poder decorarlos con el [Authorize(false)]o algo, pero esto no está disponible.

¿Algunas ideas?

Andrei Rînea
fuente

Respuestas:

100

Editar: Desde ASP.NET MVC 4, el mejor enfoque es simplemente usar el atributo AllowAnonymous incorporado .

La respuesta a continuación se refiere a versiones anteriores de ASP.NET MVC

Puede crear un atributo de autorización personalizado heredado del AuthorizeAttribute estándar con un parámetro bool opcional para especificar si la autorización es necesaria o no.

public class OptionalAuthorizeAttribute : AuthorizeAttribute
{
    private readonly bool _authorize;

    public OptionalAuthorizeAttribute()
    {
        _authorize = true;
    }

    public OptionalAuthorizeAttribute(bool authorize)
    {
        _authorize = authorize;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if(!_authorize)
            return true;

                    return base.AuthorizeCore(httpContext);
    }
}

Entonces puedes decorar tu controlador base con ese atributo:

[OptionalAuthorize]
public class ControllerBase : Controller
{
}

y para cualquier controlador que no desee autorización, simplemente use la anulación con un 'falso', por ejemplo

[OptionalAuthorize(false)]
public class TestController : ControllerBase
{
    public ActionResult Index()
    {
        return View();
    }
}
Steve Willcock
fuente
He pensado en esto, pero esperaba una solución más sencilla. Sin embargo, si "ellos" no proporcionaron uno, su solución es la mejor.
Andrei Rînea
2
Es mejor usar [AllowAnonymous]atributo.
Jaider
Espera ... ¿entonces el controlador solo respeta el atributo de la clase de nivel superior de un tipo en particular?
Triynko
¿Sabes por qué es MEJOR usar AllowAnonymous? Porque tienes un control más fino. En mi caso, estoy buscando deshabilitar los puntos finales de autorización solo para ciertos entornos, no lo necesita para localhost, por ejemplo. Esto proporciona una solución más elegante que la que iba a hacer en mi startup.cs. Estamos hablando 11 años después aquí.
sksallaj
76

Parece que ASP.NET MVC 4 'solucionó' esto agregando un atributo AllowAnonymous .

David Hayden escribió sobre esto :

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

    // ...
}
Andrei Rînea
fuente
15

Mi opinión personal sobre esto sería dividir el controlador. Simplemente cree otro controlador. Para las acciones, no necesita autenticación.

O podrías tener:

  • BaseController
    no requiere autenticación - aquí tienes todas tus "cosas básicas" :).

  • BaseAuthController : BaseController
    todas las acciones aquí requieren autenticación.

De esa manera, puede tener autenticación cuando lo desee, simplemente derivando de una clase específica.

sirrocco
fuente
6

Si solo desea que una acción no esté autorizada en un controlador autorizado, puede hacer algo como esto:

public class RequiresAuthorizationAttribute : ActionFilterAttribute
{
    private readonly bool _authorize;

    public RequiresAuthorizationAttribute()
    {
        _authorize = true;
    }

    public RequiresAuthorizationAttribute(bool authorize)
    {
        _authorize = authorize;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var overridingAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof (RequiresAuthorizationAttribute), false);

        if (overridingAttributes.Length > 0 && overridingAttributes[0] as RequiresAuthorizationAttribute != null && !((RequiresAuthorizationAttribute)overridingAttributes[0])._authorize)
            return;

        if (_authorize)
        {
            //redirect if not authenticated
            if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                //use the current url for the redirect
                var redirectOnSuccess = filterContext.HttpContext.Request.Url.AbsolutePath;

                //send them off to the login page
                //var redirectUrl = string.Format("?RedirectUrl={0}", redirectOnSuccess);
                var loginUrl = LinkBuilder.BuildUrlFromExpression<HomeController>(filterContext.RequestContext, RouteTable.Routes,
                                                                                  x => x.Login(redirectOnSuccess));
                filterContext.HttpContext.Response.Redirect(loginUrl, true);
            }
        }
    }
}
ponderático
fuente