Переопределить атрибут авторизации в ASP.NET MVC

83

У меня есть базовый класс контроллера MVC, к которому я применил атрибут Authorize, так как я хочу, чтобы почти все контроллеры (и их действия вместе) были авторизованы.

Однако мне нужно, чтобы контроллер и действие другого контроллера были неавторизованными. Я хотел иметь возможность украсить их чем- [Authorize(false)]нибудь, но этого нет.

Есть идеи?

Андрей Рыня
источник

Ответы:

101

Изменить: поскольку 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);
            }
        }
    }
}
громоздкий
источник