最新のweb api
を使用しています。
3つの異なるフィルター属性を持つコントローラーに注釈を付けますsome。
1 [Authorize]
2 [RessourceOwnerAttribute derived from AuthorizationFilterAttribute]
3 [InvalidModelStateAttribute derived from ActionFilterAttribute]
フィルターが上から下に宣言された順序で実行されるかどうかはわかりません。
web api 2.1
で実行順序を定義するにはどうすればよいですか?
https://aspnetwebstack.codeplex.com/workitem/1065#
私はまだ自分でそれを修正する必要がありますか?
ここで注意すべき点がいくつかあります。
さて、あなたが言及していると思われる問題は、同じ種類の複数フィルターを持つことに関連しています(例:コントローラーまたはアクションで複数のActionFilterAttribute
が装飾されています。反映に基づいて順序を保証します。)。この場合、System.Web.Http.Filters.IFilterProvider
のカスタム実装を使用して、Web APIでそれを行う方法があります。私は次のことを試し、それを確認するためにいくつかのテストを行いました。それはうまくいくようです。試してみて、期待どおりに動作するかどうかを確認できます。
// 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; }
}
Kiran Challaの答えからの解決策にいくつかの問題がありました。これが私の修正です。
問題はメソッドにありました
private IEnumerable<FilterInfo> OrderFilters(IEnumerable<IFilter> filters, FilterScope scope)
{
return filters.OfType<IOrderedFilter>()
.OrderBy(filter => filter.Order)
.Select(instance => new FilterInfo(instance, scope));
}
ご覧のとおりonlyIOrderedFilter
を実装するフィルターが返されます。サードパーティの属性があり、それが切り取られ、結果として実行されません。
だから私は2つの可能な解決策がありました。
IOrderFilter
も実装するようにします。IOrderFilter
属性のようなIOrderFilter
を実装していないすべての属性を処理し、IOrderFilter
属性と組み合わせて順序付けて返します。2番目の解決策は、IOrderFilter
を実装しないサードパーティの属性の前にIOrderFilter
属性を持ってくることができるためです。
[NonOrderableThirdPartyAttribute]
[OrderableAttributeA(Order = -1)]
[OrderableAttributeB(Order = 1)]
[OrderableAttributeC(Order = 2)]
public async Task<IHttpActionResult> Post(... request)
{
// do something
}
だから実行は
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);
}
}
同じ種類のフィルターが複数ある場合、実行順序は[グローバル]-> [コントローラー]-> [アクション]になります。
許可フィルターの場合、異なるレベルで複数のフィルターを設定すると、それらは「AND」と結合され、上記の実行順序で計算されます。
そして、認証プロセスは、最初に失敗したフィルターで失敗します。
詳細については、この投稿を確認してください。
https://docs.Microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.1