Синхронно получить AccessToken из HttpContext IHttpContextAccessor - PullRequest
1 голос
/ 16 апреля 2019

Мы используем ASP.NET Core 2.2 для создания проекта веб-API, который по сути является интеллектуальным прокси-сервером для другого API.Мы не хотим делать ничего особенного с токенами доступа, а просто перенаправляем их при вызове другого API.

Я хочу избежать вызовов «sync over async», особенно в конструкторах и DI-преобразователях и фабриках,все еще полагаясь на платформу для обработки извлечения токенов доступа из текущего http-запроса.

Вот репрезентативное повторение нашего сценария:

public class TheOtherApi : ITheOtherApi
{
    private readonly HttpClient _client;

    public TheOtherApi(HttpClient client, IHttpContextAccessor httpContextAccessor)
    {
        _client = client;

        // Yuck! Sync over async, inside a constructor!
        var token = httpContextAccessor.HttpContext.GetTokenAsync("access_token").Result;

        client.SetBearerToken(token);
    }

    public Task<string> ForwardSomethingCool(MyCommand command)
    {
        // E.g.
        var response await _client.PostAsync(command.path, command.body);
        return await response.Content.ReadAsStringAsync();
    }
}

Регистрация в Startup по следующим направлениям:

services.AddScoped<ITheOtherApi, TheOtherApi>();
services.AddHttpContextAccessor();
services.AddScoped(_=> new HttpClient { BaseAddress = new Uri("https://example.org/api") });

Это прекрасно демонстрирует мою проблему: там есть .Result, от которого я хочу полностью избавиться, не просто перенеся его в какую-то заводскую функцию, зарегистрированную в Startup.

Ища синхронный способ получения токена доступа, я спустился в источник GetTokenAsync(...) и посмотрел, какой другой метод я мог бы использовать intead.Я обнаружил, что на самом деле он имеет всевозможные побочные эффекты, например, он делает AuthenticateAsync(...), прежде чем делать то, что предлагает название метода («получение токена» из контекста).

Я на самом деле хочу только логику из GetTokenValue(...) без других битов и ура (!): Это не асинхронный .... но этот метод опирается на AuthenticationProperties, которого у меня нетлегко доступны из HttpContextAccessor?

Мой текущий обходной путь (или «решение»?) состоит в том, чтобы сделать работу самостоятельно:

httpContextAccessor.HttpContext.Request.Headers
    .TryGetValue("Authorization", out var authorizationHeader);

var bearerToken = authorizationHeader
    .SingleOrDefault()
    ?.Replace("bearer ", "", StringComparison.InvariantCultureIgnoreCase);

if (string.IsNullOrWhiteSpace(bearerToken))
{
    throw new ArgumentException(nameof(httpContextAccessor), "HttpContextAccessor resulted in no Access Token");
}

_client.SetBearerToken(token);

Как я мог синхронно получитьaccess_token из IHttpContextAccessor без написания собственной вспомогательной функции для заголовков / манипуляции со строками, чтобы извлечь ее из заголовков?

...