Zastąp atrybut autoryzacji w ASP.NET MVC


83

Mam klasę bazową kontrolera MVC, na której zastosowałem atrybut Autoryzuj, ponieważ chcę, aby prawie wszystkie kontrolery (i ich akcje) były autoryzowane.

Jednak potrzebuję, aby administrator i działanie innego administratora były nieuprawnione. Chciałem móc je ozdobić [Authorize(false)]czy czymś, ale to nie jest dostępne.

Jakieś pomysły?

Odpowiedzi:


101

Edycja: ponieważ ASP.NET MVC 4 najlepszym podejściem jest po prostu użycie wbudowanego atrybutu AllowAnonymous .

Poniższa odpowiedź dotyczy wcześniejszych wersji ASP.NET MVC

Można utworzyć niestandardowy atrybut autoryzacji dziedziczący po standardowym AuthorizeAttribute z opcjonalnym parametrem bool, aby określić, czy autoryzacja jest wymagana, czy nie.

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

Następnie możesz ozdobić swój podstawowy kontroler tym atrybutem:

[OptionalAuthorize]
public class ControllerBase : Controller
{
}

a dla kontrolerów, których nie chcesz autoryzować, po prostu użyj zastąpienia z wartością „fałsz” - np

[OptionalAuthorize(false)]
public class TestController : ControllerBase
{
    public ActionResult Index()
    {
        return View();
    }
}

Myślałem o tym, ale liczyłem na prostsze rozwiązanie. Jeśli jednak „oni” go nie dostarczyli, Twoje rozwiązanie jest najlepsze.
Andrei Rînea,

2
Lepiej jest użyć [AllowAnonymous]atrybutu.
Jaider

Czekaj ... więc kontroler honoruje tylko atrybut klasy najwyższego poziomu określonego typu?
Triynko

Czy wiesz, dlaczego tak naprawdę LEPSZE jest użycie AllowAnonymous? Ponieważ masz lepszą kontrolę. W moim przypadku chcę wyłączyć punkty końcowe autoryzacji tylko dla niektórych środowisk, na przykład nie potrzebujesz tego dla localhost. Zapewnia to bardziej eleganckie rozwiązanie niż to, co zamierzałem zrobić w moim startup.cs. Rozmawiamy tutaj 11 lat później.
sksallaj


15

Moim osobistym podejściem do tego byłoby podzielenie kontrolera. Po prostu utwórz kolejny kontroler Do działań, których nie potrzebujesz uwierzytelniania.

Lub możesz mieć:

  • BaseController
    nie wymaga uwierzytelniania - tutaj masz wszystkie swoje "podstawowe rzeczy" :).

  • BaseAuthController : BaseController
    wszystkie działania tutaj wymagają uwierzytelnienia.

W ten sposób możesz mieć uwierzytelnianie, kiedy chcesz, po prostu poprzez wyprowadzenie z określonej klasy.


6

Jeśli chcesz, aby tylko jedna akcja była nieautoryzowana na autoryzowanym kontrolerze, możesz zrobić coś takiego:

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);
            }
        }
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.