Как обновить токен с помощью IHttpClientFactory - PullRequest
0 голосов
/ 19 мая 2019

Я использую IHttpClientFactory для отправки запросов и получения HTTP-ответов от двух внешних API-интерфейсов с использованием Net Core 2.2.

Я ищу хорошую стратегию для получения нового токена доступа с использованием сохраненного токена обновленияв appsettings.json.Новый токен доступа необходимо запрашивать, когда текущий запрос возвращает ошибки 403 или 401. Когда новый токен доступа и обновления получены, файл appsettings.json необходимо обновить новыми значениями, чтобы использовать в последующих запросах.

Я использую два клиента для отправки запросов двум разным API, но только один из них использует механизм аутентификации токена.

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

Я зарегистрировал IHttpClientFactory в методе Startup.ConfigureServices следующим образом:

services.AddHttpClient();

После регистрации я использую его в двухразные методы для вызова двух разных API, первый метод:

   public async Task<AirCallRequest> GetInformationAsync(AirCallModel model)
    {
        try
        {


            CandidateResults modelCandidateResult = null;

            var request = new HttpRequestMessage(HttpMethod.Get,
            "https://*******/v2/*****");
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _appSettings.Value.Token);


            var clientJAAPI = _httpClientFactory.CreateClient();
            var responseclientJAAPI = await clientJAAPI.SendAsync(request);


            if (responseclientJAAPI.IsSuccessStatusCode)
            {
                modelCandidateResult = await responseclientJAAPI.Content
                   .ReadAsAsync<CandidateResults>();

                ....
            }


            if ((responseclientJAAPI .StatusCode.ToString() == "Unauthorized")
            {                    

                await RefreshAccessToken();

               //Calls recursively this method again
                return await GetInformationAsync(model);

            }

            return null;
        }
        catch (Exception e)
        {
            return null;

        }

    }

Метод Token обновления выглядит так:

private async Task RefreshAccessToken()
    {


        var valuesRequest = new List<KeyValuePair<string, string>>();
        valuesRequest.Add(new KeyValuePair<string, string>("client_id", "*****"));
        valuesRequest.Add(new KeyValuePair<string, string>("client_secret","****"));
        valuesRequest.Add(new KeyValuePair<string, string>("grant_type", "refresh_token"));
        valuesRequest.Add(new KeyValuePair<string, string>("refresh_token", "*****"));


        RefreshTokenResponse refreshTokenResponse = null;

        var request = new HttpRequestMessage(HttpMethod.Post,
        "https://*****/connect/token");

        request.Content = new FormUrlEncodedContent(valuesRequest);

        var clientJAAPI = _httpClientFactory.CreateClient();
        var responseclientJAAPI = await clientJAAPI.SendAsync(request);

        if (responseclientJAAPI.IsSuccessStatusCode)
        {
            refreshTokenResponse = await responseclientJAAPI.Content.ReadAsAsync<RefreshTokenResponse>();

            //this updates the POCO object representing the configuration but not the appsettings.json :
            _appSettings.Value.Token = refreshTokenResponse.access_token;

        }

    }

Обратите внимание, что я обновляю объект POCO, представляющий конфигурациюно не appsettings.json, поэтому новые значенияхранится в памяти.Я хочу обновить appsettings.json для последующих запросов.

Если предлагаемое решение требует определения основных параметров для Httpclient в Startup.ConfigureService, ему необходимо разрешить создание разных экземпляров HttpClien, поскольку один из экземпляров HttpClient (используйте в другом методе для вызовавторой API) не требует токен для отправки запросов.

1 Ответ

1 голос
/ 19 мая 2019

Похоже, вам нужно DelegatingHandler .В двух словах вы можете «перехватить» ваш http-запрос и добавить заголовок авторизации, затем попытаться выполнить его, и, если токен недействителен, обновить токен и повторить попытку еще раз.Примерно так:

public class AuthenticationDelegatingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var token = await GetToken();
        request.Headers.Authorization = new AuthenticationHeaderValue(token.Scheme, token.AccessToken);
        var response = await base.SendAsync(request, cancellationToken);

        if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden)
        {
            token = await RefreshToken();
            request.Headers.Authorization = new AuthenticationHeaderValue(token.Scheme, token.AccessToken);
            response = await base.SendAsync(request, cancellationToken);
        }

        return response;
    }
}

Вы регистрируете этот делегирующий обработчик в Startup.cs так:

services.AddTransient<AuthenticationDelegatingHandler>();
services.AddHttpClient("MySecuredClient", client =>
    {
        client.BaseAddress = new Uri("https://baseUrl.com/");
    })
    .AddHttpMessageHandler<AuthenticationDelegatingHandler>();

И используете вот так:

var securedClient = _httpClientFactory.CreateClient("MySecuredClient");
securedClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "v2/relativeUrl"));

По поводу хранения обновлениятокен в appsetting.json.Я не думаю, что это хорошая идея, так как освежающий ток не имеет срока годности.Если вы можете использовать учетные данные для получения нового токена в первый раз, используйте его, а затем сохраните токен обновления в памяти для дальнейшего обновления.

Здесь вы можете увидеть, как управлять учетными данными клиентатокен обновляется и попытается заставить его работать в вашем сценарии.

...