Avatar ·

Установка заголовка Authorization для HttpClient в C# (OAuth, REST)

Всем привет! Я новичок в C# и пытаюсь отправить GET-запрос к REST API, который требует аутентификацию через OAuth 2.0. У меня есть Bearer-токен (access_token), который я получаю от сервера авторизации. Проблема в том, что я не могу правильно установить заголовок Authorization для HttpClient. API возвращает ошибку 401 Unauthorized, хотя токен точно рабочий (проверял в Postman). Мой код выглядит так: ```csharp using (var client = new HttpClient()) { client.BaseAddress = new Uri("https://api.example.com/"); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var response = await client.GetAsync("/v1/users"); // ... обработка ответа } ``` Я пробовал также добавлять заголовок вручную через `client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token)`, но результат тот же. Что я делаю не так? Может быть, проблема в том, что я неправильно задаю BaseAddress или нужно использовать другой подход для Windows Runtime (UWP)? Буду благодарен за подробное объяснение с примерами. <<>>

Правильная установка заголовка Authorization

Ваш код в целом верен, но есть несколько распространенных ошибок, которые могут вызывать проблему. Давайте разберем их по порядку.

1. Проверьте, что токен не содержит лишних символов

Самая частая причина — токен содержит пробелы, кавычки или символы перевода строки. Убедитесь, что вы передаете именно строку токена без лишних символов. Лучше всего обрезать строку:

token = token.Trim();

2. Используйте правильный способ установки заголовка

Ваш первый вариант с AuthenticationHeaderValue — это правильный подход. Но если он не работает, попробуйте явно указать схему и значение:

client.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Bearer", token);

Убедитесь, что строка "Bearer" написана с большой буквы и без лишних пробелов.

3. Проблема с BaseAddress и относительным URI

Если вы используете BaseAddress, то относительный URI в GetAsync должен начинаться с "/". Ваш код корректен, но проверьте, что BaseAddress заканчивается на "/":

client.BaseAddress = new Uri("https://api.example.com/"); // обязательно слэш в конце

4. Для UWP/Windows Runtime — используйте HttpClientHandler

Если вы работаете в UWP-приложении, может потребоваться явно настроить обработчик:

var handler = new HttpClientHandler();
using (var client = new HttpClient(handler))
{
    client.DefaultRequestHeaders.Authorization = 
        new AuthenticationHeaderValue("Bearer", token);
    var response = await client.GetAsync("https://api.example.com/v1/users");
}

5. Альтернативный способ — создание запроса вручную

Если ничего не помогает, попробуйте создать запрос вручную и задать заголовок непосредственно перед отправкой:

using (var client = new HttpClient())
{
    var request = new HttpRequestMessage(HttpMethod.Get, 
        "https://api.example.com/v1/users");
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var response = await client.SendAsync(request);
}

6. Проверьте, не переопределяется ли заголовок

Иногда заголовок может быть переопределен автоматически (например, при редиректах). Чтобы избежать этого, отключите автоматическое следование редиректам:

var handler = new HttpClientHandler();
handler.AllowAutoRedirect = false;
using (var client = new HttpClient(handler)) { ... }

7. Отладка — проверьте, что отправляется на самом деле

Используйте перехватчик трафика (Fiddler, Wireshark) или логирование, чтобы увидеть, какой заголовок реально отправляется. Можно временно вывести заголовки в консоль:

foreach (var header in client.DefaultRequestHeaders)
{
    Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
}

Скорее всего, проблема в одном из этих пунктов. Начните с проверки токена и способа установки заголовка.

<<>>

Альтернативный подход: использование DelegatingHandler

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

public class AuthHandler : DelegatingHandler
{
    private readonly string _token;
    
    public AuthHandler(string token, HttpMessageHandler innerHandler = null)
        : base(innerHandler ?? new HttpClientHandler())
    {
        _token = token;
    }
    
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
        return await base.SendAsync(request, cancellationToken);
    }
}

// Использование:
var authHandler = new AuthHandler(token);
var client = new HttpClient(authHandler);
client.BaseAddress = new Uri("https://api.example.com/");
var response = await client.GetAsync("/v1/users");

Этот подход особенно полезен, если токен может обновляться (например, при использовании refresh_token). Вы можете добавить логику обновления токена внутри обработчика.

Также рекомендую не создавать новый HttpClient для каждого запроса, а использовать один экземпляр (или пул экземпляров) для всего приложения — это улучшит производительность и предотвратит утечку сокетов.