Заголовок HttpContext - PullRequest
       1

Заголовок HttpContext

1 голос
/ 23 апреля 2019

Я создал этот класс для получения значения заголовка из запросов.

public class AuthenticationHeader
{
    private static  IHttpContextAccessor _httpContextAccessor;
    public AuthenticationHeader(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public string AuthHeader => _httpContextAccessor.HttpContext?.Request.Headers["Authorization"];

}

и что я зарегистрировал это в своем startup.cs, как это

services.AddSingleton<AuthenticationHeader>();

И это было введено в мои другие классы, как это.

public BaseClient(HttpClient client, ILogger<BaseClient> logger, AuthenticationHeader authHeader)
{
    _client = client;
    client.BaseAddress = new Uri("yrl");
    client.DefaultRequestHeaders.Add("Accept", "application/json");
    _logger = logger;
    AuthHeader = authHeader;
}

Теперь, когда я зарегистрировал это как Singleton. Поэтому, когда я вызываю мой API впервые и предоставляю значение Authorization в заголовке, api вызывается успешно, но проблема в том, что когда я передаю пустой заголовок Authorization, он все равно успешно вызывает api, так как хранит старое значение заголовка из-за Singleton. Как я могу это исправить? Есть ли другие способы сделать то, что я делаю.

1 Ответ

1 голос
/ 23 апреля 2019

Попробуйте использовать HttpClientFactory, который был добавлен Asp.Net Core 2.1, вместе с HttpMessageHandler для достижения того, что вы пытаетесь сделать.

Вы можете зарегистрировать HttpClient в методе ConfigureServices

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient<BaseClient>(client =>
    {
        client.BaseAddress = new Uri("yrl");
        client.DefaultRequestHeaders.Add("Accept", "application/json");
        c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
        c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
    });
 }

При наличии вышеуказанного кода ваш BaseClient получит экземпляр HttpClient через DI.

Для проверки / проверки AuthHeader вы можете настроить HttpMessageHandlerдля зарегистрированных HttpClient.Код для обработчика сообщений прост, как показано ниже:

public class AuthHeaderHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (!request.Headers.Contains("Authorization"))
        {
            return new HttpResponseMessage(HttpStatusCode.Forbidden)
            {
                Content = new StringContent("No Authorization header is present")
            };
        }

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

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

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<AuthHeaderHandler>();
    services.AddHttpClient<BaseClient>(client =>
     {
         //code omitted for brevity
         ...
     })
      .AddHttpMessageHandler<AuthHeaderHandler>();
 }

Вы можете ввести все, что вам нужновнутри обработчика сообщений, если это необходимо.Однако нет необходимости внедрять IHttpContextAccessor в BaseClient.Чтобы узнать больше о HttpClientFactory и HttpMessageHandlers, перейдите по ссылкам и по .Я надеюсь, что это поможет.

ОБНОВЛЕННЫЙ ОТВЕТ

Пожалуйста, взгляните на более конкретный пример HttpMessageHandler, который использует IHttpContextAccessor и изменяет HttpRequestMessage, т.е. добавляет заголовок авторизации перед тем, какзвонок сделан.Вы можете изменить логику в соответствии со своими потребностями.

public class AuthHeaderHandler : DelegatingHandler
{
    private readonly HttpContext _httpContext;

    public AuthHeaderHandler(IHttpContextAccessor contextAccessor)
    {
        _httpContext = contextAccessor.HttpContext;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (_httpContext != null)
        {
            var accessToken = await _httpContext.GetTokenAsync(TokenKeys.Access);
            if (!string.IsNullOrEmpty(accessToken))
            {
                // modify the request header with the new Authorization token
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            }
        }

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

ОБНОВЛЕННЫЙ ОТВЕТ 2

Пожалуйста, взгляните на простое решение , которое язагрузили на GitHub.Решение даже проще, чем я изначально предлагал.Поскольку вы не интегрируете аутентификацию / авторизацию на основе идентификации, вы можете просто использовать CustomActionFilter, я назвал его ValidateAuthHeader, чтобы проверить, присутствует ли AuthHeader или нет, и вернуть обычные 403, если таковые отсутствуют.

В ValidateAuthHeader я использовал код промежуточного программного обеспечения, который вы разместили ранее.Затем вы можете просто добавить этот атрибут в ActionMethods или Controllers, которые требуют этой проверки.

Пожалуйста, посмотрите на DataController и ValuesController.DataController получит напечатанный HttpClient, который будет использоваться для вызова конечной точки values.ValidateAuthHeader присутствует на GetValues и проверит наличие AuthHeader.Если он отсутствует, он выдаст ошибку.

[Route("api/[controller]")]
[ApiController]
public class DataController : ControllerBase
{
    private readonly MyHttpClient _client;

    public DataController(MyHttpClient client)
    {
        _client = client;
    }

    [ValidateAuthHeader]
    public async Task<IActionResult> GetValues()
    {
        var response = await _client.GetAsync("api/values");

        var contents = await response.Content.ReadAsStringAsync();

        return new ContentResult
        {
            Content = contents,
            ContentType = "application/json",
            StatusCode = 200
        };
    }
}

Остальная часть потока такая же, как я изначально предлагал.Вызов будет проходить через AuthHeaderHandler, который является HttpMessageHandler для зарегистрированного MyHttpClient.Пожалуйста, посмотрите на Startup.cs.

. Обработчик извлечет HttpContext через HttpContextAccessor и проверит наличие AuthHeader.Если он присутствует, он добавит его в параметр RequestMessage.

Надеюсь, это поможет.Не стесняйтесь задавать любые вопросы, которые могут у вас возникнуть.

Настройка заголовка аутентификации без использования HttpMessageHandler

Измените MyHttpClient и добавьте открытый метод с именем SetAuthHeader

public class MyHttpClient
{
    private readonly HttpClient _httpClient;

    public MyHttpClient(HttpClient client)
    {
        _httpClient = client;
    }

    public void SetAuthHeader(string value)
    {
        _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", value);
    }
}

Затем вызовите этот метод в своем методе действия, так как в этот момент у вас будет AuthHeader в HttpContext.Request

[ValidateAuthHeader]
public async Task<IActionResult> GetValues()
{
    var authHeader = Request.Headers["Authorization"];

    _client.SetAuthHeader(authHeader.First());

    var response = await _client.GetAsync("api/values");

    var contents = await response.Content.ReadAsStringAsync();

    return new ContentResult
    {
        Content = contents,
        ContentType = "application/json",
        StatusCode = 200
    };
}

Удалите регистрацию AuthHeaderHandler и удалите AuthHeaderHandler.

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