Refit и OAuth-аутентификация в c #, почему опять Http - PullRequest
0 голосов
/ 13 мая 2018

Я только что узнал о библиотеке Refit на GitHub (ссылка: https://github.com/reactiveui/refit). Помимо своих первых шагов в этом огромном мире, я попытался понять, почему использование этой библиотеки удобно вместо использования обычного HttpClient , когда нам нужно сделать http-вызовы, например, для службы API. Читая вокруг, я понял причину, по которой мы сами создаем httpClient, устанавливаем заголовки и другие конфигурации. , это слишком старый стиль и низкоуровневый. Вот где происходит переустановка. Затем я попытался сделать один шаг вперед и прочитать о части аутентификации. Я заметил, согласно странице библиотеки github, что для того, чтобы аутентификация работала нам нужно снова разобраться с HttpClient , от которого нам наконец удалось избавиться. Пример, показанный на официальной странице:

class AuthenticatedHttpClientHandler : HttpClientHandler
{
    private readonly Func<Task<string>> getToken;

    public AuthenticatedHttpClientHandler(Func<Task<string>> getToken)
    {
        if (getToken == null) throw new ArgumentNullException("getToken");
        this.getToken = getToken;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // See if the request has an authorize header
        var auth = request.Headers.Authorization;
        if (auth != null)
        {
            var token = await getToken().ConfigureAwait(false);
            request.Headers.Authorization = new AuthenticationHeaderValue(auth.Scheme, token);
        }

        return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
    }
}

class LoginViewModel
{
    AuthenticationContext context = new AuthenticationContext(...);
    private async Task<string> GetToken()
    {
        // The AcquireTokenAsync call will prompt with a UI if necessary
        // Or otherwise silently use a refresh token to return
        // a valid access token 
        var token = await context.AcquireTokenAsync("http://my.service.uri/app", "clientId", new Uri("callback://complete"));

        return token;
    }

    public async void LoginAndCallApi()
    {
        var api = RestService.For<IMyRestService>(new HttpClient(new AuthenticatedHttpClientHandler(GetToken)) { BaseAddress = new Uri("https://the.end.point/") });

        var location = await api.GetLocationOfRebelBase();
    }
}

Мне интересно, какую концепцию я здесь упускаю. Цель библиотеки - использовать более высокоуровневый код, устанавливая интерфейсы, достаточные для вызова службы API. Эта цель достигается до аутентификации, потому что все настройки Http и т. Д. Сделаны специально под капотом. Но как только мы вступаем в это поле, мы снова находим HttpHandlers, HttpRequestMessages и HttpClients, теряя то, что является целью самой библиотеки. Может кто-нибудь объяснить мне, пожалуйста, что я упускаю в общей картине? заранее спасибо

1 Ответ

0 голосов
/ 21 июля 2019

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

TL; DR: есть альтернативы для установки аутентификации, которые не требуют использования HttpClient, наблюдения 2и 3 ниже.

Существует как минимум три способа обработки аутентификации:

1) Как отмечено на странице GitHub, вы можете передать HttpClient с помощью HttpClientHandler, а в обработчике установитьЗаголовок авторизации.С точки зрения того, почему вам нужно использовать обработчик, я заметил, что Refit установит заголовок Authorization на любое значение, указанное в атрибуте, перед выполнением HTTP-запроса, если вы установили заголовок в HttpClient до создания экземпляра Refit.не будет работать, например, это не будет работать:

[Get("/secretStuff")]
[Headers("Authorization: Bearer")]
Task<Location> GetLocationOfRebelBase();
. . .
var client = new HttpClient() { BaseAddress = new Uri("https://the.end.point/") };
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", someToken);
var api = RestService.For<IMyRestService>(client);
var location = await api.GetLocationOfRebelBase();

Заголовок Авторизации будет "Авторизация: Носитель", токена там не будет.Вам необходимо изменить HttpClient непосредственно перед выполнением HTTP-запроса в HttpClientHandler (или DelgatingHandler).

2) При создании нового экземпляра клиента Refit api передайте базовый адрес RestService.Вместо HttpClient и укажите AuthorizationHeaderValueGetter, например:

var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com", new RefitSettings {
   AuthorizationHeaderValueGetter = () => {
     var token = SomeMethodToGetAToken();
     Task.FromResult(token);
   }
});

3) Передайте токен в метод api, например:

[Get("/users/{user}")]
Task<User> GetUser(string user, [Header("Authorization")] string authorization);

Это упоминается на странице Refit GitHub: https://github.com/reactiveui/refit#dynamic-headers.

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