Как передать объекты между `HandleAuthenticateAsync` и` HandleChallengeAsync` в моем собственном `AuthenticationHandler`? - PullRequest
0 голосов
/ 10 июля 2019

Я не могу найти правильный способ передачи объектов из HandleAuthenticateAsync, где находится мой пользовательский код аутентификации, в обратный вызов HandleChallengeAsync, где я обрабатываю сбой аутентификации и задаю код состояния ответа и тело.

Если аутентификация не удалась, я хочу вернуть объект JSON, который содержит некоторую информацию в теле ответа о том, почему аутентификация не удалась.

В моем коде обработчика я хочу сериализовать некоторые значения из resultsв методе HandleChallengeAsync:

public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions>
{
    public const string ApiKeyHeaderName = "X-API-KEY";

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

    // The authentication handler that gets call for every request (including `[AllowAnonymous]`
    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        Request.Headers.TryGetValue(Options.ApiKeyHeaderName, out var apiKeyHeaderValues);
        var key = apiKeyHeaderValues.FirstOrDefault();

        var results = await new AuthenticateApiKeyQuery(key).Results();

        if (results.HasErrors())
            return AuthenticateResult.Fail("Useless message that doesn't go anywhere");

        return Success(results.Value);
    }

    // the callback that gets called for any `[Authorize]` actions
    override protected async Task HandleChallengeAsync(AuthenticationProperties properties)
    {
        var errors = new { }; // I want `errors` to come from the `result` object above
        Context.Response.StatusCode = 401;
        Context.Response.ContentType = "application/json";
        var json = Newtonsoft.Json.JsonConvert.SerializeObject(errors);
        await Context.Response.Body.WriteAsync(System.Text.Encoding.UTF8.GetBytes(json));
    }

    // Method that sent up the identity/claim etc
    private AuthenticateResult Success(ApiKey apiKey)
    {
        var claims = new List<Claim>()
        {
            new Claim(ClaimTypes.NameIdentifier, apiKey.ID.ToString()),
            new Claim(ClaimTypes.Name, apiKey.Description),
        };

        var identity = new ClaimsIdentity(claims, Options.AuthenticationType);
        var identities = new List<ClaimsIdentity> { identity };
        var principal = new ClaimsPrincipal(identities);
        var ticket = new AuthenticationTicket(principal, Options.AuthenticationScheme);

        return AuthenticateResult.Success(ticket);
    }

В моей первоначальной попытке метод HandleAuthenticateAsync установил 401 и тело ответа.Это не работает, так как обработчик аутентификации также запускается для действий, помеченных [AllowAnonymous].В результате ответом будет 401 и сериализованный JSON, а не статус и ответ, заданные действием.Принимая во внимание, что HandleChallengeAsync вызывается только в случае сбоя аутентификации и для действия требуется авторизация.

Это не самый простой код для навигации, но, как я могу сказать, PolicyEvalulator вызывает AuthenticationHandler, которыйзатем вызывает мой кастом HandleAuthenticateAsync.AuthenticateResult, который я возвращаю, затем поглощается PolicyEvalulator, поэтому я не могу использовать его для хранения любых значений для дальнейшей обработки.Я еще не выяснил, что называется моим обычаем HandleChallengeAsync, но к этому моменту AuthenticateResult был поглощен.

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