ASP.NET Core Web应用中消费JWT Token的配置及存储问题咨询
ASP.NET Core Web应用消费JWT Token解决方案
一、Token存储方案
优先选择加密HttpOnly Cookie存储JWT Token,该方案可避免XSS攻击窃取Token,安全性远高于前端localStorage/sessionStorage,适配传统MVC、Razor Pages架构的Web应用。
配置Cookie认证服务
在Program.cs中添加如下配置:
using Microsoft.AspNetCore.Authentication.Cookies; var builder = WebApplication.CreateBuilder(args); // 注册Cookie认证服务 builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Account/Login"; // 未授权时跳转的登录页路径 options.Cookie.HttpOnly = true; // 禁止前端JS读取Cookie,防XSS options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // 生产环境强制HTTPS传输 options.ExpireTimeSpan = TimeSpan.FromHours(2); // 过期时间和JWT Token过期时间对齐 options.SlidingExpiration = true; // 活跃用户自动续期 }); // 其他服务注册... builder.Services.AddControllersWithViews(); builder.Services.AddHttpContextAccessor(); var app = builder.Build(); // 中间件顺序必须严格遵循:静态文件 -> 路由 -> 认证 -> 授权 -> 端点映射 app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); // 必须放在UseAuthorization之前 app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
登录逻辑实现
用户提交账号密码后调用JWT认证服务接口获取Token,再将Token写入认证Cookie,示例代码如下:
public class AccountController : Controller { private readonly IHttpClientFactory _httpClientFactory; public AccountController(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } [HttpPost] public async Task<IActionResult> Login(LoginModel model) { if (!ModelState.IsValid) return View(model); // 调用JWTAuthentication服务端登录接口获取Token var authClient = _httpClientFactory.CreateClient(); var response = await authClient.PostAsJsonAsync("JWT认证服务登录接口地址", new { model.Username, model.Password }); if (!response.IsSuccessStatusCode) { ModelState.AddModelError("", "账号或密码错误"); return View(model); } var tokenResult = await response.Content.ReadFromJsonAsync<TokenResponse>(); var accessToken = tokenResult.AccessToken; // 把Token存入Claims,后续请求可直接读取 var claims = new List<Claim> { new Claim(ClaimTypes.Name, model.Username), new Claim("AccessToken", accessToken) }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity)); return RedirectToAction("Index", "Home"); } } // 自定义类用于接收Token返回结果 public class TokenResponse { public string AccessToken { get; set; } public int ExpiresIn { get; set; } } public class LoginModel { [Required] public string Username { get; set; } [Required] public string Password { get; set; } }
二、API请求自动携带Token配置
通过自定义委托处理程序,实现所有发往受保护API的请求自动添加Authorization头,无需每个请求手动编写逻辑。
自定义请求委托处理程序
public class JwtTokenHandler : DelegatingHandler { private readonly IHttpContextAccessor _httpContextAccessor; public JwtTokenHandler(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // 从当前登录用户的Claims中读取AccessToken var accessToken = _httpContextAccessor.HttpContext?.User.Claims .FirstOrDefault(c => c.Type == "AccessToken")?.Value; if (!string.IsNullOrEmpty(accessToken)) { // 把Token加到请求头 request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } return await base.SendAsync(request, cancellationToken); } }
注册服务并配置HttpClient
在Program.cs中添加如下配置:
// 注册自定义JWT请求处理程序 builder.Services.AddTransient<JwtTokenHandler>(); // 配置访问受保护API的HttpClient,自动应用JWT头 builder.Services.AddHttpClient("ProtectedApiClient", client => { client.BaseAddress = new Uri("AnyAPI服务根地址"); client.DefaultRequestHeaders.Add("Accept", "application/json"); }).AddHttpMessageHandler<JwtTokenHandler>(); // 挂载自定义处理程序
API调用示例
无需手动处理Token,直接使用配置好的HttpClient即可:
public class HomeController : Controller { private readonly IHttpClientFactory _httpClientFactory; public HomeController(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task<IActionResult> Index() { // 直接用配置好的HttpClient调用API,自动携带JWT Token var apiClient = _httpClientFactory.CreateClient("ProtectedApiClient"); var data = await apiClient.GetFromJsonAsync<List<YourDataModel>>("目标API接口路径"); return View(data); } }
注意事项
- 如果Web应用是Blazor WASM架构,可选择将Token存储在
localStorage,配合AuthorizationMessageHandler实现自动携带请求头 - Cookie的过期时间需要和JWT服务返回的Token过期时间保持一致,避免出现Cookie有效但Token已过期的问题
- 生产环境必须启用Cookie的SecurePolicy,仅允许HTTPS传输Cookie,避免中间人攻击窃取信息
内容的提问来源于stack exchange,提问作者Patibandha
相关产品推荐
相关产品推荐

