首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HttpContext报头

HttpContext报头
EN

Stack Overflow用户
提问于 2019-04-23 11:43:29
回答 1查看 10.1K关注 0票数 4

我创建了这个类,用于从请求中获取标头值。

代码语言:javascript
复制
public class AuthenticationHeader
{
    private static  IHttpContextAccessor _httpContextAccessor;
    public AuthenticationHeader(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

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

}

我已经在我的startup.cs上这样注册了

代码语言:javascript
复制
services.AddSingleton<AuthenticationHeader>();

像这样注入到我的其他课程中。

代码语言:javascript
复制
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并在头中提供授权值时,api被成功地调用,但问题是当我传递空的授权头时,它仍然成功地调用了它的api,因为它由于Singleton而存储旧的标头值。我怎么才能解决这个问题?还有其他方法来做我正在做的事吗。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-04-23 14:13:04

尝试使用HttpClientFactory,即添加了Asp.Net Core2.1和HttpMessageHandler,以实现您想要做的事情。

您可以在HttpClient方法中注册ConfigureServices

代码语言:javascript
复制
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将通过DI接收HttpClient实例。

为了验证/检查AuthHeader,可以为注册的HttpClient配置HttpMessageHandler。消息处理程序的代码很简单,如下所示:

代码语言:javascript
复制
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);
    }
}

为了注册上述处理程序,代码如下所示:

代码语言:javascript
复制
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,即在调用之前添加授权头。您可以根据需要修改逻辑。

代码语言:javascript
复制
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的GitHub。解决办法比我原先建议的要简单得多。由于您没有集成任何基于身份的身份验证/授权,所以只需使用CustomActionFilter (我称之为ValidateAuthHeader )来检查AuthHeader是否存在,如果不存在,则返回通常的403。

ValidateAuthHeader中,我使用了您之前发布的中间件代码。然后,您可以简单地在需要此检查的ActionMethods或控制器上添加此属性。

请看一下DataControllerValuesControllerDataController将接收用于调用values端点的类型化HttpClientValidateAuthHeader出现在GetValues上,并将检查AuthHeader。如果不存在,就会产生错误。

代码语言:javascript
复制
[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传递,这是注册MyHttpClientHttpMessageHandler。请看一下Startup.cs

处理程序将通过HttpContext通过HttpContextAccessor检索该AuthHeader,并检查AuthHeader。如果存在,它将将其添加到RequestMessage参数中。

我希望这能帮到你。请随便问你可能有的任何问题。

不使用HttpMessageHandler设置Auth标头

修改MyHttpClient并添加一个名为SetAuthHeader的公共方法

代码语言:javascript
复制
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中。

代码语言:javascript
复制
[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。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55810466

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档