Подтвердить что ты не робот

AllowAnonymous не работает с Custom AuthorizationAttribute

Это немного озадачило меня. По-видимому, ни одна из часто встречающихся аналогичных ситуаций, по-видимому, не применяется. Я, вероятно, пропустил что-то очевидное, но я не вижу его.

В моем веб-приложении Mvc я использую атрибуты Authorize и AllowAnonymous таким образом, что вы должны явно открыть действие как общедоступное, а не блокировать безопасные области сайта. Я предпочитаю этот подход. Однако я не могу получить такое же поведение в своем WebAPI.

Я написал специальный атрибут авторизации, который наследует от System.Web.Http.AuthorizeAttribute следующее:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class MyAuthorizationAttribute : System.Web.Http.AuthorizeAttribute

Я зарегистрировал его как фильтр:

    public static void RegisterHttpFilters(HttpFilterCollection filters)
    {
        filters.Add(new MyAuthorizationAttribute());
    }

Все работает так, как ожидалось, действия больше не доступны без учетных данных. Проблема в том, что теперь следующий метод не позволит атрибуту AllowAnonymous делать это:

[System.Web.Http.AllowAnonymous]
public class HomeController : ApiController
{
    [GET("/"), System.Web.Http.HttpGet]
    public Link[] Index()
    {
        return new Link[] 
        { 
            new SelfLink(Request.RequestUri.AbsoluteUri, "api-root"),
            new Link(LinkRelConstants.AuthorizationEndpoint, "OAuth/Authorize/", "authenticate"),
            new Link(LinkRelConstants.AuthorizationTokenEndpoint , "OAuth/Tokens/", "auth-token-endpoint")
        };
    }
}

Наиболее распространенным сценарием, похоже, является смешение двух атрибутов Authorize/AllowAnonymous. System.Web.Mvc предназначен для веб-приложений, а System.Web.Http - для WebAPI (как я понимаю, так или иначе).

Оба атрибута, которые я использую, принадлежат одному пространству имен - System.Web.Http. Я предположил, что это просто наследует базовую функциональность и позволяет мне вводить код, который мне нужен в методе OnAuthotize.

В соответствии с документацией атрибут AllowAnonymous работает внутри метода OnAuthorize, который я вызываю сразу:

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        base.OnAuthorization(actionContext);

Любая мысль была бы оценена по достоинству.

Кто-нибудь столкнулся с этой проблемой раньше и нашел основную причину?

4b9b3361

Ответ 1

В Author AuthorAttribute есть следующий код:

private static bool SkipAuthorization(HttpActionContext actionContext)
{
    Contract.Assert(actionContext != null);

    return actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()
               || actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
}

Включите этот метод в свой класс AuthorizeAttribute, а затем добавьте следующее в начало вашего метода OnAuthorization, чтобы пропустить авторизацию, если найдены атрибуты AllowAnonymous:

if (SkipAuthorization(actionContext)) return;

Ответ 2

ASP.NET MVC 4:

bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)
                         || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);

или

 private static bool SkipAuthorization(AuthorizationContext filterContext)
    {
        Contract.Assert(filterContext != null);

        return filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any()
               || filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any();
    }

Сорвали: http://weblogs.asp.net/jongalloway/asp-net-mvc-authentication-global-authentication-and-allow-anonymous

Ответ 3

Использование С# 6.0 Создайте статический класс, который расширяет ActionExecutingContext.

public static class AuthorizationContextExtensions {
    public static bool SkipAuthorization(this ActionExecutingContext filterContext) {    
         Contract.Assert(filterContext != null);
         return filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any()|| filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any();
    }
}

Теперь ваш переопределяющий filterContext сможет вызвать метод расширения, просто убедитесь, что они находятся в одном и том же пространстве имен или включают правильный оператор using.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeCustomAttribute : ActionFilterAttribute {
    public override void OnActionExecuting(ActionExecutingContext filterContext) {
        if (filterContext.SkipAuthorization()) return;// CALL EXTENSION METHOD
         /*NOW DO YOUR LOGIC FOR NON ANON ACCESS*/
    }
}

Ответ 4

Я должен использовать другую версию .net framework или web api, но, надеюсь, это кому-то помогает:

        bool skipAuthorization = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any() || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
        if (skipAuthorization)
        {
            return;
        }