Remplacer l'attribut d'autorisation dans ASP.NET MVC

83

J'ai une classe de base de contrôleur MVC sur laquelle j'ai appliqué l'attribut Authorize car je veux que presque tous les contrôleurs (et leurs actions) soient autorisés.

Cependant, je dois avoir un contrôleur et une action d'un autre contrôleur non autorisé. Je voulais pouvoir les décorer avec le [Authorize(false)]ou quelque chose mais ce n'est pas disponible.

Des idées?

Andrei Rînea
la source

Réponses:

100

Edit: Depuis ASP.NET MVC 4, la meilleure approche consiste simplement à utiliser l' attribut AllowAnonymous intégré .

La réponse ci-dessous fait référence aux versions antérieures d'ASP.NET MVC

Vous pouvez créer un attribut d'autorisation personnalisé héritant de l'AutorizeAttribute standard avec un paramètre booléen facultatif pour spécifier si l'autorisation est requise ou non.

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);
    }
}

Ensuite, vous pouvez décorer votre contrôleur de base avec cet attribut:

[OptionalAuthorize]
public class ControllerBase : Controller
{
}

et pour tous les contrôleurs que vous ne voulez pas d'autorisation, utilisez simplement le remplacement avec un 'faux' - par exemple

[OptionalAuthorize(false)]
public class TestController : ControllerBase
{
    public ActionResult Index()
    {
        return View();
    }
}
Steve Willcock
la source
J'y ai pensé mais j'espérais une solution plus simple. Cependant, si «ils» n'en ont pas fourni, votre solution est la meilleure.
Andrei Rînea le
2
Il est préférable d'utiliser l' [AllowAnonymous]attribut.
Jaider
Attendez ... pour que le contrôleur n'honore que l'attribut de la classe de premier niveau d'un type particulier?
Triynko
Savez-vous pourquoi il est préférable d'utiliser AllowAnonymous? Parce que vous avez un contrôle plus fin. Dans mon cas, je cherche à désactiver les points de terminaison d'autorisation uniquement pour certains environnements, vous n'en avez pas besoin pour localhost par exemple. Cela fournit une solution plus élégante que ce que j'allais faire dans mon startup.cs. Nous parlons 11 ans plus tard ici.
sksallaj
76

Il semble que ASP.NET MVC 4 a «corrigé» ce problème en ajoutant un attribut AllowAnonymous .

David Hayden a écrit à ce sujet :

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

    // ...
}
Andrei Rînea
la source
15

Mon point de vue personnel serait de diviser le contrôleur. Créez simplement un autre contrôleur Pour les actions, vous n'avez pas besoin d'authentification.

Ou vous pourriez avoir:

  • BaseController
    ne nécessite pas d'authentification - ici vous avez tous vos "trucs de base" :).

  • BaseAuthController : BaseController
    toutes les actions ici nécessitent une authentification.

De cette façon, vous pouvez avoir une authentification quand vous le souhaitez, simplement en dérivant d'une classe spécifique.

sirrocco
la source
6

Si vous voulez juste qu'une action ne soit pas autorisée sur un contrôleur par ailleurs autorisé, vous pouvez faire quelque chose comme ceci:

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);
            }
        }
    }
}
pondermatique
la source