ASP.NET JWT Bearer控制器无法获取用户数据问题排查
JWT Bearer 配置问题排查:Profile控制器无法获取用户数据
问题描述
我正在学习JWT Bearer的使用,不确定配置是否正确。注册流程一切正常,但在Profile控制器中无法获取用户数据,不清楚是项目配置还是控制器代码存在问题。
项目配置代码
builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; }).AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "meuf", // 替换为你自己的值 ValidAudience = "meufCorporation", // 替换为你自己的值 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")) // 替换为你自己的值 }; }).AddCookie(options => { options.Cookie.Name = "Cookies"; }); builder.Services.AddAuthorization(); // 向容器添加服务 builder.Services.AddControllersWithViews(); var app = builder.Build(); // 配置HTTP请求管道 if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); // 默认HSTS值为30天,生产环境可根据需要修改 app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.Use(async (context, next) => { // 从请求头获取令牌 string token = context.Request.Headers["Authorization"]; if (!string.IsNullOrEmpty(token) && token.StartsWith("Bearer ")) { // 移除"Bearer "前缀 token = token.Substring("Bearer ".Length).Trim(); // 验证并解析令牌 var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.UTF8.GetBytes("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); var validationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key) }; try { var principal = tokenHandler.ValidateToken(token, validationParameters, out var validatedToken); if (principal.Identity is ClaimsIdentity identity) { // 获取令牌中的所有声明 var claims = identity.Claims.ToList(); // 创建name声明,值为用户标识,并添加到声明列表 var userIdClaim = new Claim("name", principal.Identity.Name); claims.Add(userIdClaim); // 使用更新后的声明创建新的ClaimsIdentity var newIdentity = new ClaimsIdentity(claims, identity.AuthenticationType, identity.NameClaimType, identity.RoleClaimType); // 为当前用户设置新的ClaimsIdentity context.User = new ClaimsPrincipal(newIdentity); } } catch (Exception ex) { // 处理令牌解析或验证错误 Console.WriteLine($"令牌验证错误: {ex.Message}"); } } await next(); }); app.UseRouting(); app.UseAuthorization(); app.UseAuthentication(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
控制器代码
[AutoValidateAntiforgeryToken] [HttpGet] [AllowAnonymous] public async Task<IActionResult> Profile() { var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); if (string.IsNullOrEmpty(userId)) { return View(); // 处理用户未认证或无用户标识的情况 } if (Guid.TryParse(userId, out Guid currentUserId)) { var currentUser = await _dbContext.Users.FindAsync(currentUserId); if (currentUser == null) { return NotFound(); // 处理未找到用户的情况 } ViewData["Username"] = currentUser.UserName; ViewData["Email"] = currentUser.Email; return View(); } else { return View(); // 处理id无法转换为Guid的情况 } }
问题分析与修复方案
核心问题点
- 中间件顺序错误:
app.UseAuthorization()在app.UseAuthentication()之前执行,导致授权逻辑先于认证逻辑运行,此时User对象还未被认证中间件填充,自然无法获取用户数据。 - 冗余的自定义令牌解析中间件:你已经通过
AddJwtBearer配置了官方的JWT认证中间件,无需自己编写令牌解析逻辑。自定义中间件不仅重复工作,还使用了不完整的验证参数(未验证Issuer、Audience、令牌有效期),且添加的name声明与控制器需要的ClaimTypes.NameIdentifier不匹配。 - 控制器特性配置不当:
[AllowAnonymous]会跳过授权检查,框架可能不会触发认证流程,导致User对象始终为空或未正确填充。
修复步骤
- 移除自定义令牌解析中间件:删除整个
app.Use(async (context, next) => { ... })代码块,依赖官方AddJwtBearer的内置逻辑即可。 - 调整中间件顺序:将认证与授权中间件的顺序修正为:
app.UseRouting(); app.UseAuthentication(); // 先认证 app.UseAuthorization(); // 后授权 - 修正控制器特性:移除
[AllowAnonymous],添加[Authorize]确保只有认证用户能访问Profile接口:[AutoValidateAntiforgeryToken] [HttpGet] [Authorize] // 替换AllowAnonymous public async Task<IActionResult> Profile() { // 原有代码不变 } - 确保JWT令牌包含正确声明:在生成JWT令牌时,必须添加
ClaimTypes.NameIdentifier类型的声明,值为用户的Guid ID,示例代码:var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), // 关键声明 new Claim(ClaimTypes.Name, user.UserName), // 其他需要的声明 }; var token = new JwtSecurityToken( issuer: "meuf", audience: "meufCorporation", claims: claims, expires: DateTime.Now.AddHours(1), signingCredentials: new SigningCredentials( new SymmetricSecurityKey(Encoding.UTF8.GetBytes("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")), SecurityAlgorithms.HmacSha256 ) ); return new JwtSecurityTokenHandler().WriteToken(token);
内容的提问来源于stack exchange,提问作者Gadzila Grom
相关产品推荐
相关产品推荐

