Cela m'a stoppé pendant un moment. Aucune des situations similaires fréquemment rencontrées ne semble s'appliquer ici apparemment. J'ai probablement manqué quelque chose d'évident mais je ne le vois pas.
Dans mon application Web Mvc, j'utilise les attributs Authorize et AllowAnonymous de manière à ce que vous deviez ouvrir explicitement une action comme étant accessible au public plutôt que verrouiller les zones sécurisées du site. Je préfère de beaucoup cette approche. Je ne peux cependant pas avoir le même comportement dans mon WebAPI.
J'ai écrit un attribut d'autorisation personnalisé qui hérite de System.Web.Http.AuthorizeAttribute avec les éléments suivants:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class MyAuthorizationAttribute : System.Web.Http.AuthorizeAttribute
Je l'ai enregistré comme filtre:
public static void RegisterHttpFilters(HttpFilterCollection filters)
{
filters.Add(new MyAuthorizationAttribute());
}
Tout cela fonctionne comme prévu, les actions ne sont plus disponibles sans informations d'identification. Le problème est que maintenant la méthode suivante n'autorisera pas l'attribut 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")
};
}
}
Le scénario le plus courant semble être de confondre les deux attributs Authorize/AllowAnonymous. System.Web.Mvc est destiné aux applications Web et System.Web.Http à WebAPI (comme je le comprends de toute façon).
Les deux attributs que j'utilise proviennent du même espace de noms, System.Web.Http. J'ai supposé que cela hériterait simplement de la fonctionnalité de base et me permettrait d'injecter le code dont j'ai besoin dans la méthode OnAuthotize.
Selon la documentation, l'attribut AllowAnonymous fonctionne dans la méthode OnAuthorize que j'appelle immédiatement:
public override void OnAuthorization(HttpActionContext actionContext)
{
base.OnAuthorization(actionContext);
Toute pensée serait vraiment appréciée.
Quelqu'un at-il déjà rencontré ce problème et trouvé la cause première?
AuthorizeAttribute contient le code suivant:
private static bool SkipAuthorization(HttpActionContext actionContext)
{
Contract.Assert(actionContext != null);
return actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()
|| actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
}
Incluez cette méthode dans votre classe AuthorizeAttribute puis ajoutez ce qui suit en haut de votre méthode OnAuthorization pour ignorer l'autorisation si des attributs AllowAnonymous sont trouvés:
if (SkipAuthorization(actionContext)) return;
ASP.NET MVC 4:
bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)
|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
ou
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();
}
Utilisation de C # 6.0 Créez une classe statique qui étend 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();
}
}
Désormais, votre filtre filterContext pourra appeler la méthode d’extension. Assurez-vous simplement qu’ils se trouvent dans le même espace-noms ou incluez l’instruction using appropriée.
[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*/
}
}
Je dois utiliser une version différente du framework .net ou de l'API Web, mais j'espère que cela aidera quelqu'un:
bool skipAuthorization = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any() || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
if (skipAuthorization)
{
return;
}
Utilisation de MVC 5
Étapes pour surmonter ce problème: -
1. Mettez à jour votre attribut anonyme de projet WebAPI et faites-le comme
[System.Web.Mvc.AllowAnonymous]
Maintenant, allez dans votre classe d'attributs personnalisés et écrivez le code
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext filterContext)
{
if (filterContext == null)
{
throw new UnauthorizedAccessException("Access Token Required");
}
base.OnAuthorization(filterContext);
if (filterContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
{
return;
}
if (filterContext.Request.Headers.Authorization != null)
{
var response =
PTPRestClient.GetRequest(filterContext.Request.Headers.Authorization.ToString(),
"api/validate/validate-request");
if (!response.IsSuccessStatusCode)
{
throw new UnauthorizedAccessException();
}
}
else
{
throw new UnauthorizedAccessException("Access Token Required");
}
}
public class MyAuthorizationAuthorize : AuthorizeAttribute, IAuthorizationFilter
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) ||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
if (skipAuthorization) return;
}
else filterContext.Result = new HttpUnauthorizedResult();
}
}