You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET MVC/Web API如何跨控制器设置带Token的默认请求头?

解决ASP.NET MVC中HttpClientFactory自动添加Token请求头的问题

一、选择合适的Token存储方式

对于单服务器部署场景,Session是最易上手的选择;如果是多服务器集群,推荐使用IDistributedCache(如Redis)存储Token,保证跨服务器共享。以下以Session为例讲解。

二、实现自定义DelegatingHandler

创建继承自DelegatingHandler的类,负责在每次HttpClient发送请求前,从存储中取出Token并添加到请求头:

public class TokenAuthorizationHandler : DelegatingHandler
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public TokenAuthorizationHandler(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var httpContext = _httpContextAccessor.HttpContext;
        if (httpContext != null)
        {
            // 从Session中获取Token
            var token = httpContext.Session.GetString("AuthToken");
            if (!string.IsNullOrEmpty(token))
            {
                // 添加Bearer Token到请求头
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
            }
        }

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

三、在Program.cs中配置服务

  1. 启用Session和HttpContextAccessor服务:
var builder = WebApplication.CreateBuilder(args);

// 配置Session
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(30);
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});

// 注册HttpContextAccessor,用于在Handler中访问当前请求上下文
builder.Services.AddHttpContextAccessor();

// 注册自定义Token处理Handler
builder.Services.AddTransient<TokenAuthorizationHandler>();
  1. 配置命名HttpClient并关联自定义Handler:
// 注册命名HttpClient,绑定API基础地址并添加Token处理逻辑
builder.Services.AddHttpClient("ProtectedApiClient", client =>
{
    client.BaseAddress = new Uri("https://your-api-base-url/");
})
.AddHttpMessageHandler<TokenAuthorizationHandler>();
  1. 启用Session中间件(注意顺序:放在UseRouting之后,UseAuthorization之前):
var app = builder.Build();

// ...其他中间件配置

app.UseRouting();

// 启用Session
app.UseSession();

app.UseAuthorization();

// ...其他中间件配置

app.Run();

四、登录后存储Token

在登录控制器中,调用登录API获取Token后将其存入Session:

public class AccountController : Controller
{
    private readonly IHttpClientFactory _httpClientFactory;

    public AccountController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        if (!ModelState.IsValid) return View(model);

        var client = _httpClientFactory.CreateClient("ProtectedApiClient");
        var loginResponse = await client.PostAsJsonAsync("api/auth/login", model);

        if (loginResponse.IsSuccessStatusCode)
        {
            var tokenResult = await loginResponse.Content.ReadFromJsonAsync<TokenResponse>();
            // 将Token存入Session
            HttpContext.Session.SetString("AuthToken", tokenResult.AccessToken);
            return RedirectToAction("Index", "Home");
        }

        ModelState.AddModelError("", "登录失败,请检查用户名或密码");
        return View(model);
    }
}

// 定义Token响应模型
public class TokenResponse
{
    public string AccessToken { get; set; }
    public int ExpiresIn { get; set; }
}

// 登录视图模型
public class LoginViewModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}

五、在其他控制器中使用带Token的HttpClient

直接注入IHttpClientFactory,创建命名客户端即可自动携带Token请求头:

public class HomeController : Controller
{
    private readonly IHttpClientFactory _httpClientFactory;

    public HomeController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    public async Task<IActionResult> GetProtectedData()
    {
        var client = _httpClientFactory.CreateClient("ProtectedApiClient");
        var response = await client.GetAsync("api/protected/data");

        if (response.IsSuccessStatusCode)
        {
            var data = await response.Content.ReadFromJsonAsync<ProtectedData>();
            return View(data);
        }

        return View("Error");
    }
}

// 受保护数据模型
public class ProtectedData
{
    public string Content { get; set; }
}

注意事项

  • 多服务器部署时,将Session替换为IDistributedCache,注入IDistributedCache后用await _distributedCache.GetStringAsync("AuthToken")获取Token。
  • 可在TokenAuthorizationHandler中添加Token过期检测和自动刷新逻辑,避免Token失效导致请求失败。
  • 生产环境建议启用HTTPS,并设置Session Cookie的Secure属性,提升安全性。

内容的提问来源于stack exchange,提问作者Zul Huky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 01:04:54