ASP.NET Core 2.2 Web API:如何将JWT受众设为请求客户端域名?
首先得明确一个核心概念:你用Request.Host拿到的本来就是API服务自身的域名,这是正常的——因为Request.Host描述的是当前请求发送到的目标地址,而客户端的域名其实是放在**Origin请求头**里的,这是跨域请求(CORS)的标准头。
你的临时中间件思路是对的,但确实不够优雅,而且如果没做严格校验的话还存在安全风险。下面是更符合ASP.NET Core规范的实现方式:
一、核心逻辑:从Origin头获取客户端域名并校验安全
跨域AJAX请求时,浏览器会自动在请求头里带上Origin,值就是发起请求的客户端域名。但不能直接用这个值,必须先校验它是否在你的合法来源列表里(和CORS配置的CorsAllowedForOrigins保持一致),避免恶意站点伪造Origin获取非法Token。
1. 生成JWT时的规范代码
在你的Token生成接口里,先获取并校验Origin,再用它作为audience:
[HttpPost("generate-token")] public IActionResult GenerateToken() { // 1. 从请求头获取客户端Origin var clientOrigin = Request.Headers["Origin"].FirstOrDefault(); // 2. 复用CORS的合法来源列表做校验 var allowedOrigins = APIConstants.CorsAllowedForOrigins .Replace(" ", string.Empty) .Split(',') .ToList(); if (string.IsNullOrEmpty(clientOrigin) || !allowedOrigins.Contains(clientOrigin)) { // 非法Origin,返回错误 return BadRequest("Invalid client origin. Only allowed domains can request tokens."); } // 3. 生成带正确audience的JWT var creds = new SigningCredentials( new SymmetricSecurityKey(Encoding.UTF8.GetBytes(APIConstants.TokenSecret)), SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: APIConstants.TokenIssuer, audience: clientOrigin, // 这里用校验后的客户端Origin expires: DateTime.Now.AddDays(APIConstants.TokenExpireAfter), signingCredentials: creds); return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) }); }
2. 优化CORS配置,去掉自定义中间件
ASP.NET Core的原生CORS中间件已经能自动处理合法Origin的校验和响应头设置,完全不需要手动修改Access-Control-Allow-Origin:
services.AddCors(o => o.AddPolicy("GlablEnableCorsPolicy", builder => { var allowedOrigins = APIConstants.CorsAllowedForOrigins .Replace(" ", string.Empty) .Split(',') .ToArray(); builder.WithOrigins(allowedOrigins) .WithMethods(APIConstants.CorsAllowedForMethods.Replace(" ", string.Empty).Split(',')) .AllowAnyHeader() .AllowCredentials(); // 如果你的请求需要带Cookie/认证头,加上这个 }));
然后记得在Startup.cs的Configure方法里启用CORS(要放在UseAuthentication之前):
app.UseCors("GlablEnableCorsPolicy"); app.UseAuthentication(); app.UseMvc();
二、关键注意事项
- 同域请求的处理:如果客户端和API同域,请求不会带
Origin头,这时候可以设置一个默认的audience,或者根据业务场景处理(比如用API自身域名作为默认audience)。 - 安全第一:绝对不能跳过Origin的校验,否则恶意站点可以伪造Origin,获取针对自己域名的JWT,绕过你的受众校验逻辑。
- 配置复用:确保JWT校验的
ValidAudiences和CORS的allowedOrigins用的是同一个配置源,避免出现配置不一致导致的错误。
为什么你的临时中间件不够优雅?
自定义中间件手动修改Access-Control-Allow-Origin会绕过ASP.NET Core原生的CORS校验逻辑,如果后续修改了合法来源列表,中间件没同步更新的话,就会出现安全漏洞。而原生CORS机制会自动帮你完成Origin校验、响应头设置,还能处理预检请求(OPTIONS),更可靠也更符合框架规范。
内容的提问来源于stack exchange,提问作者LearningNeverEnds

