Перевизначити атрибут авторизації в ASP.NET MVC


83

У мене є базовий клас контролера MVC, до якого я застосував атрибут Authorize, оскільки хочу, щоб майже всі контролери (та їх дії разом) були авторизовані.

Однак мені потрібно мати контролер та дію іншого контролера несанкціоновано. Я хотів мати можливість прикрасити їх тим [Authorize(false)]чи іншим, але це недоступно.

Будь-які ідеї?

Відповіді:


100

Редагувати: Оскільки ASP.NET MVC 4, найкращим підходом є просто використання вбудованого атрибута AllowAnonymous .

Відповідь нижче стосується попередніх версій ASP.NET MVC

Ви можете створити власний атрибут авторизації, що успадковується від стандартного AuthorizeAttribute, з необов’язковим параметром bool, щоб вказати, чи потрібна авторизація чи ні.

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

Тоді ви можете прикрасити свій базовий контролер таким атрибутом:

[OptionalAuthorize]
public class ControllerBase : Controller
{
}

а для будь-яких контролерів, яким ви не хочете авторизації, просто використовуйте перевизначення із значенням "false" - наприклад

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

Я думав про це, але сподівався на більш просте рішення. Однак якщо "вони" не надали такого, то ваше рішення є найкращим.
Андрій Рінеа,

2
Краще використовувати [AllowAnonymous]атрибут.
Jaider

Зачекайте ... так контролер відзначає лише атрибут класу верхнього рівня певного типу?
Трійко

Чи знаєте ви, чому насправді КРАЩЕ використовувати AllowAnonymous? Тому що ви маєте більш точний контроль. У моєму випадку я прагну відключити кінцеві точки авторизації лише для певних середовищ, наприклад, вам це не потрібно для localhost. Це забезпечує більш елегантне рішення, ніж те, що я збирався зробити у своєму startup.cs. Ми говоримо тут через 11 років.
sksallaj


15

Моїм особистим завданням було б розділити контролер. Просто створіть інший контролер. Для дій вам не потрібна автентифікація.

Або ви можете мати:

  • BaseController
    не вимагає автентифікації - тут у вас є всі ваші "базові речі" :).

  • BaseAuthController : BaseController
    всі дії тут вимагають автентифікації.

Таким чином, ви можете мати автентифікацію, коли хочете, просто походить з певного класу.


6

Якщо ви просто хочете, щоб одна дія була несанкціонована на іншому авторизованому контролері, ви можете зробити щось подібне:

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);
            }
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.