#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
атрибут. Похоже, это невозможно. Если только я чего-то не упускаю?