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);
Любая мысль была бы оценена по достоинству.
Кто-нибудь столкнулся с этой проблемой раньше и нашел основную причину?
Ответы
Ответ 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;
}