programing

웹 API에서 여러 필터를 사용한 실행 순서

muds 2023. 8. 4. 23:21
반응형

웹 API에서 여러 필터를 사용한 실행 순서

최신 버전을 사용하고 있습니다.web api.

3가지 필터 특성을 가진 일부 컨트롤러에는 주석을 달지 않습니다.

1 [Authorize]
2 [RessourceOwnerAttribute derived from AuthorizationFilterAttribute]
3 [InvalidModelStateAttribute derived from ActionFilterAttribute]

필터가 위에서 아래로 선언된 순서대로 실행되는지 확신할 수 없습니다.

다음에서 실행 순서를 정의하려면 어떻게 합니까?web api 2.1?

https://aspnetwebstack.codeplex.com/workitem/1065 #

http://aspnet.uservoice.com/forums/147201-asp-net-web-api/suggestions/3346720-execution-order-of-mvc4-webapi-action-filters

제가 아직도 그걸 스스로 고쳐야 하나요?

여기서 주의해야 할 몇 가지 사항:

  1. 필터는 작업에 대해 다음 순서로 실행됩니다.전역적으로 정의된 필터 -> 컨트롤러별 필터 -> 작업별 필터.
  2. 권한 부여 필터 -> 작업 필터 -> 예외 필터
  3. 이제 언급하신 것처럼 보이는 문제는 같은 종류의 필터를 여러 개 갖는 것과 관련이 있습니다(예: 다중).ActionFilterAttribute컨트롤러 또는 동작에 장식됩니다.이것은 반영에 근거한 주문을 보증하지 않는 경우입니다.)이 경우, 웹 API에서 사용자 정의 구현을 사용하는 방법이 있습니다.System.Web.Http.Filters.IFilterProvider저는 다음을 시도했고 그것을 검증하기 위해 몇 가지 테스트를 했습니다.잘 될 것 같습니다.한 번 시도해 보시고 예상하신 대로 작동하는지 확인해보세요.

    // 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));
}

를 구현하는 필터만 볼 수 있습니다.IOrderedFilter돌려받을 것입니다.타사 속성이 삭제되어 실행되지 않았습니다.

그래서 저는 두 가지 가능한 해결책이 있었습니다.

  1. 상속을 사용하여 타사 특성의 확장 버전을 만들어 구현IOrderFilter너무.
  2. 구현하지 않는 모든 속성을 처리하도록 방법 변경IOrderFilter좋아해를IOrderFilter순서 번호가 0인 속성과 결합합니다.IOrderFilter속성을 정렬하고 반환합니다.

두 번째 해결책은 내가 나의 것을 가져올 수 있게 해주기 때문에 더 낫습니다.IOrderFilter구현하지 않는 타사 특성 앞의 특성IOrderFilter.

샘플

[NonOrderableThirdPartyAttribute]
[OrderableAttributeA(Order = -1)]
[OrderableAttributeB(Order = 1)]
[OrderableAttributeC(Order = 2)]
public async Task<IHttpActionResult> Post(... request) 
{
    // do something
}

그래서 사형 집행은

  • 주문 가능한 속성 A
  • 주문 불가서드 파티 속성
  • 순서 가능한 속성 B
  • 순서 가능한 속성 C

그래서 여기 수정된 코드가 있습니다.

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);
    }
}

asp.net core에서 IOrderedFilter를 사용하여 관리할 수 있습니다.

public class MyFilter : IActionFilter, IOrderedFilter
{
    public int Order => 1; // define the order here
    ...
}

같은 종류의 필터가 여러 개 있는 경우 실행 순서는 글로벌 -> 컨트롤러 -> 액션입니다.

권한 부여 필터의 경우 여러 필터를 다른 수준으로 설정하면 "AND"와 결합되어 위의 실행 순서로 계산됩니다.

그리고 첫 번째 실패한 필터에서 인증 프로세스가 실패합니다.

자세한 내용은 이 게시물을 확인하시면 됩니다.

https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.1

MVC에서 여러 필터가 구현되는 경우 실행 순서는 다음과 같습니다.

  1. 권한 부여 필터
  2. 작업 필터
  3. 결과 필터
  4. 예외 필터

언급URL : https://stackoverflow.com/questions/21628467/order-of-execution-with-multiple-filters-in-web-api

반응형