Возвращать пользовательский ответ при использовании атрибута Authorize на контроллере - PullRequest
0 голосов
/ 26 марта 2020

Я только что реализовал токен Bearer, и я добавил атрибут Authorize в мой класс контроллера, и это прекрасно работает. Это выглядит следующим образом:

[Authorize (AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

Я хотел бы создать более сложный ответ от сервера в случае сбоя, а не стандарт 401.

Я пробовал фильтры, но они вообще не запускаются.

Есть идеи, как это сделать?

1 Ответ

1 голос
/ 26 марта 2020

Иметь собственную схему, пользовательский обработчик авторизации и пуф!

Обратите внимание, что я ввел обработчик в ConfigureServices:

services.AddAuthentication(options =>
            {
                options.DefaultScheme = ApiKeyAuthenticationOptions.DefaultScheme;
                options.DefaultAuthenticateScheme = ApiKeyAuthenticationOptions.DefaultScheme;
            })
                .AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>(
                    ApiKeyAuthenticationOptions.DefaultScheme, o => { });

ApiKeyAuthenticationOptions

public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions
    {
        public const string DefaultScheme = "API Key";
        public string Scheme => DefaultScheme;
        public string AuthenticationType = DefaultScheme;
        public const string HeaderKey = "X-Api-Key";
    }

ApiKeyAuthenticationHandler

    /// <summary>
    /// An Auth handler to handle authentication for a .NET Core project via Api keys.
    ///
    /// This helps to resolve dependency issues when utilises a non-conventional method.
    /// https://stackoverflow.com/questions/47324129/no-authenticationscheme-was-specified-and-there-was-no-defaultchallengescheme-f
    /// </summary>
    public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions>
    {
        private readonly IServiceProvider _serviceProvider;

        public ApiKeyAuthenticationHandler(IOptionsMonitor<ApiKeyAuthenticationOptions> options, ILoggerFactory logger, 
            UrlEncoder encoder, ISystemClock clock, IServiceProvider serviceProvider) 
            : base (options, logger, encoder, clock) 
        {
            _serviceProvider = serviceProvider;
        }

        protected override Task<AuthenticateResult> HandleAuthenticateAsync() 
        {
            var token = Request.Headers[ApiKeyAuthenticationOptions.HeaderKey];

            if (string.IsNullOrEmpty(token)) {
                return Task.FromResult (AuthenticateResult.Fail ("Token is null"));
            }

            var customRedisEvent = _serviceProvider.GetRequiredService<ICustomRedisEvent>();
            var isValidToken = customRedisEvent.Exists(token, RedisDatabases.ApiKeyUser);

            if (!isValidToken) {
                return Task.FromResult (AuthenticateResult.Fail ($"Invalid token {token}."));
            }

            var claims = new [] { new Claim ("token", token) };
            var identity = new ClaimsIdentity (claims, nameof (ApiKeyAuthenticationHandler));
            var ticket = new AuthenticationTicket (new ClaimsPrincipal (identity), Scheme.Name);
            return Task.FromResult (AuthenticateResult.Success (ticket));
        }
    }

Сосредоточиться на классе обработчика. Помимо предоставленного мною примера кода, просто используйте свойства базового класса, такие как Response, чтобы установить свой собственный код статуса http или все, что вам может понадобиться!

Вот производный класс, если вам это нужно. https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.authenticationhandler-1?view=aspnetcore-3.1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...