J'utilise le dernier web api
.
J'annote certains contrôleurs avec 3 attributs de filtre différents.
1 [Authorize]
2 [RessourceOwnerAttribute derived from AuthorizationFilterAttribute]
3 [InvalidModelStateAttribute derived from ActionFilterAttribute]
Je ne peux pas être sûr que les filtres fonctionnent dans l'ordre dans lequel ils ont été déclarés, de haut en bas.
Comment définir l'ordre d'exécution dans web api 2.1
?
https://aspnetwebstack.codeplex.com/workitem/1065#
Dois-je toujours régler ce problème moi-même ??
Quelques points à noter ici:
Maintenant, le problème que vous semblez mentionner est lié au fait que Ayant plusieurs filtres du même genre (ex: Multiple ActionFilterAttribute
décoré sur un contrôleur pas garantir l'ordre comme basé sur la réflexion.). Dans ce cas, il existe un moyen De le faire dans Web API en utilisant une implémentation personnalisée de System.Web.Http.Filters.IFilterProvider
. J'ai essayé le suivant Et fait quelques tests pour le vérifier. Cela semble marcher correctement. Vous pouvez essayer et voir si cela fonctionne comme prévu.
// Start clean by replacing with filter provider for global configuration.
// For these globally added filters we need not do any ordering as filters are
// executed in the order they are added to the filter collection
config.Services.Replace(typeof(IFilterProvider), new System.Web.Http.Filters.ConfigurationFilterProvider());
// Custom action filter provider which does ordering
config.Services.Add(typeof(IFilterProvider), new OrderedFilterProvider());
public class OrderedFilterProvider : IFilterProvider
{
public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
// controller-specific
IEnumerable<FilterInfo> controllerSpecificFilters = OrderFilters(actionDescriptor.ControllerDescriptor.GetFilters(), FilterScope.Controller);
// action-specific
IEnumerable<FilterInfo> actionSpecificFilters = OrderFilters(actionDescriptor.GetFilters(), FilterScope.Action);
return controllerSpecificFilters.Concat(actionSpecificFilters);
}
private IEnumerable<FilterInfo> OrderFilters(IEnumerable<IFilter> filters, FilterScope scope)
{
return filters.OfType<IOrderedFilter>()
.OrderBy(filter => filter.Order)
.Select(instance => new FilterInfo(instance, scope));
}
}
//NOTE: Here I am creating base attributes which you would need to inherit from.
public interface IOrderedFilter : IFilter
{
int Order { get; set; }
}
public class ActionFilterWithOrderAttribute : ActionFilterAttribute, IOrderedFilter
{
public int Order { get; set; }
}
public class AuthorizationFilterWithOrderAttribute : AuthorizationFilterAttribute, IOrderedFilter
{
public int Order { get; set; }
}
public class ExceptionFilterWithOrderAttribute : ExceptionFilterAttribute, IOrderedFilter
{
public int Order { get; set; }
}
La solution de Kiran Challa me posait quelques problèmes .. Voici ma modification.
Le problème était dans la méthode
private IEnumerable<FilterInfo> OrderFilters(IEnumerable<IFilter> filters, FilterScope scope)
{
return filters.OfType<IOrderedFilter>()
.OrderBy(filter => filter.Order)
.Select(instance => new FilterInfo(instance, scope));
}
Comme vous pouvez le constater, les filtres uniquement qui implémentent IOrderedFilter
seront renvoyés. J'ai eu un attribut tiers qui est coupé et en conséquence non exécuté.
J'ai donc eu deux solutions possibles.
IOrderFilter
.IOrderFilter
comme un attribut IOrderFilter
avec le numéro de commande 0 et combinez-le avec les attributs IOrderFilter
, commandez-le et renvoyez-le. La deuxième solution est préférable car elle me permet d’apporter mon attribut IOrderFilter
avant des attributs tiers qui n’implémentent pas IOrderFilter
.
[NonOrderableThirdPartyAttribute]
[OrderableAttributeA(Order = -1)]
[OrderableAttributeB(Order = 1)]
[OrderableAttributeC(Order = 2)]
public async Task<IHttpActionResult> Post(... request)
{
// do something
}
Donc l'exécution serait
public class OrderedFilterProvider : IFilterProvider
{
public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
// controller-specific
var controllerSpecificFilters = OrderFilters(actionDescriptor.ControllerDescriptor.GetFilters(), FilterScope.Controller);
// action-specific
var actionSpecificFilters = OrderFilters(actionDescriptor.GetFilters(), FilterScope.Action);
return controllerSpecificFilters.Concat(actionSpecificFilters);
}
private IEnumerable<FilterInfo> OrderFilters(IEnumerable<IFilter> filters, FilterScope scope)
{
// get all filter that dont implement IOrderedFilter and give them order number of 0
var notOrderableFilter = filters.Where(f => !(f is IOrderedFilter))
.Select(instance => new KeyValuePair<int, FilterInfo>(0, new FilterInfo(instance, scope)));
// get all filter that implement IOrderFilter and give them order number from the instance
var orderableFilter = filters.OfType<IOrderedFilter>().OrderBy(filter => filter.Order)
.Select(instance => new KeyValuePair<int, FilterInfo>(instance.Order, new FilterInfo(instance, scope)));
// concat lists => order => return
return notOrderableFilter.Concat(orderableFilter).OrderBy(x => x.Key).Select(y => y.Value);
}
}
Si vous avez plusieurs filtres du même type, l'ordre d'exécution sera Global -> Controller -> Action
Et pour le filtre d'autorisation, si vous définissez plusieurs filtres à différents niveaux, ils seront combinés avec un "ET" et seront calculés dans l'ordre d'exécution ci-dessus.
Et le processus d'autorisation échouera au premier filtre défaillant.
Pour plus de détails, vous pouvez consulter ce post.
https://docs.Microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.1