OnAuthorizationAsync не вызывается при создании настраиваемого AuthorizeFilter, который наследуется от AuthorizeFilter

#asp.net-core #asp.net-core-webapi #asp.net-core-3.1

#asp.net-core #asp.net-core-webapi #asp.net-core-3.1

Вопрос:

Я создал пользовательский фильтр авторизации, который выглядит следующим образом:

 public class BearerTokenAuthorizeFilter : AuthorizeFilter
{        
    public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        await base.OnAuthorizationAsync(context);
        if (context.Result is ChallengeResult)
        {
            // Then return a problem detail
            ObjectResult result = new ObjectResult(new ProblemDetails
            {
                Type = ProblemDetailsTypes.Unauthorized,
                Title = ReasonPhrases.GetReasonPhrase(StatusCodes.Status401Unauthorized),
                Status = StatusCodes.Status401Unauthorized,
                Detail = ProblemDetailsDescriptions.Unauthorized
            });
            result.ContentTypes.Add(new MediaTypeHeaderValue(new Microsoft.Extensions.Primitives.StringSegment("application/problem json")));
            
            context.Result = resu<
            await context.HttpContext.ChallengeAsync();
        }
        else if (context.Result is ForbidResult)
        {
            context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            await context.HttpContext.ForbidAsync();
        }
    }
}
 

Я регистрирую этот фильтр следующим образом:

 services.AddMvcCore(options =>
{
    options.Filters.Add<BearerTokenAuthorizeFilter>();
});
 

Я установил аутентификацию по умолчанию на «предъявителя»:

 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
 

Я добавил Authorize атрибут в контроллер. Всякий раз, когда я отправляю несанкционированный запрос на конечную точку, мой пользовательский фильтр никогда не вызывается, и я понятия не имею, почему? Моя цель — вернуть сведения о проблеме, если запрос неавторизован, чтобы предоставить потребителю немного больше информации, чем просто код состояния. Почему мой фильтр не вызывается?

Комментарии:

1. Пожалуйста, проверьте порядок промежуточного программного обеспечения в методе Configure в файле Startup.cs, убедитесь, что вы добавили промежуточное программное обеспечение UseAuthentication и UseAuthentication, код, подобный этому: app.UseAuthentication();app.UseAuthorization(); .

Ответ №1:

Попробуйте реализовать IAuthorizationFilter или IAsyncAuthorizationFilter вместо AuthorizeFilter . Это работает для меня. Также я заметил, что GetFilter(..) метод возвращает AuthorizeFilter экземпляр непосредственно AuthorizationApplicationModelProvider при реализации класса filter AuthorizeFilter . Но когда filter реализуется IAuthorizationFilter или IAsyncAuthorizationFilter этот метод не вызывается, я думаю, что это проблема в сети ASP

Комментарии:

1. Я думаю, проблема заключалась в том, что я пометил контроллеры Authorize атрибутом, а не с. BearerTokenAuthorize Итак, мой пользовательский фильтр никогда не вызывался.

Ответ №2:

В итоге я реализовал свой собственный IControllerModelConvention класс, который выглядит следующим образом:

 public class BearerTokenAuthorizeConvention : IControllerModelConvention
{
    private AuthorizationPolicy _policy;

    public BearerTokenAuthorizeConvention(AuthorizationPolicy policy)
    {
        _policy = policy;
    }        
    public void Apply(ControllerModel controller)
    {
        if (controller.Filters.OfType<BearerTokenAuthorizeFilter>().FirstOrDefault() == null)
        {
            //default policy only used when there is no authorize filter in the controller
            controller.Filters.Add(new BearerTokenAuthorizeFilter(_policy));
        }
    }
}
 

Это будет выполняться один раз для каждого контроллера. Затем я зарегистрировал это соглашение следующим образом:

 // Configure application filters and conventions
services.Configure<MvcOptions>(options =>
{
    AuthorizationPolicy defaultPolicy = new AuthorizationOptions().DefaultPolicy;
    options.Conventions.Add(new BearerTokenAuthorizeConvention(defaultPolicy));
});
 

На этом этапе каждый контроллер, который у меня есть, будет помечен этим пользовательским фильтром, который будет вызывать базовую реализацию AuthorizeFilter . Причина, по которой я хотел получить результат AuthorizeFilter , заключалась в том, что я хотел вызвать реализацию по умолчанию Authorize , а затем самостоятельно обработать неудачный ответ. Я думал, что смогу выполнить эту самую функциональность и каким-то образом все еще смогу использовать только Authorize атрибут. Похоже, это невозможно. Если только я чего-то не упускаю?