如何在ASP.NET Core 8.0中处理基于JWT的无密码自定义认证
ASP.NET Core 8 Razor应用JWT登录及Bearer头处理方案
1. 完善JWT认证配置(Program.cs)
默认的AddJwtBearer缺少必要的验证规则,需要补充令牌校验参数,确保令牌来自可信系统且Audience(用户名)合法:
builder.Services.AddAuthentication(options => { // Razor Pages适合用Cookie作为默认认证方案,维持服务器端会话 options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; // 保留JwtBearer方案,用于API接口或特定请求的令牌验证 options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddCookie(options => { options.LoginPath = "/Login"; // 指定登录页路径 options.ExpireTimeSpan = TimeSpan.FromHours(2); // Cookie过期时长 }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = "你的可信系统Issuer标识", // 替换为实际签发方标识 ValidateAudience = true, // 若需动态验证Audience(如用户名唯一),可注释ValidAudience,改用下方回调 // ValidAudience = "允许的用户范围", ValidateLifetime = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("你的签名密钥")), // 与可信系统密钥一致 ValidateIssuerSigningKey = true, // 自定义Audience验证逻辑(比如从数据库校验用户名是否存在) AudienceValidator = (audiences, token, parameters) => { return audiences.Any(a => IsValidUser(a)); // 替换为实际用户校验方法 } }; }); builder.Services.AddAuthorization(); var app = builder.Build(); // 务必添加认证、授权中间件,顺序不能错 app.UseAuthentication(); app.UseAuthorization();
2. 登录流程实现(登录页PageModel)
用户提交JWT令牌后,先手动验证令牌有效性,通过后创建身份凭证并完成登录:
Login.cshtml.cs代码
public class LoginModel : PageModel { [BindProperty] public string JwtToken { get; set; } public async Task<IActionResult> OnPostAsync() { if (string.IsNullOrEmpty(JwtToken)) { ModelState.AddModelError("", "请输入JWT令牌"); return Page(); } var tokenHandler = new JwtSecurityTokenHandler(); var validationParams = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = "你的可信系统Issuer标识", ValidateAudience = true, ValidateLifetime = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("你的签名密钥")), ValidateIssuerSigningKey = true }; try { // 验证令牌并获取身份凭证 ClaimsPrincipal principal = tokenHandler.ValidateToken(JwtToken, validationParams, out _); // 提取Audience作为用户名,再次校验合法性 string username = principal.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Aud)?.Value; if (string.IsNullOrEmpty(username) || !IsValidUser(username)) { ModelState.AddModelError("", "令牌对应的用户不存在"); return Page(); } // 用Cookie认证方案完成登录,生成会话Cookie await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties { ExpiresUtc = DateTimeOffset.UtcNow.AddHours(2), IsPersistent = true // 开启"记住我" }); return RedirectToPage("/Index"); // 登录成功跳转首页 } catch (SecurityTokenException ex) { ModelState.AddModelError("", $"令牌无效:{ex.Message}"); return Page(); } } // 自定义用户校验方法(示例:替换为数据库查询逻辑) private bool IsValidUser(string username) { return !string.IsNullOrEmpty(username); } }
Login.cshtml页面代码
@page @model LoginModel <h1>JWT登录</h1> <form method="post"> <div class="mb-3"> <label class="form-label">JWT令牌</label> <textarea asp-for="JwtToken" class="form-control" rows="6"></textarea> <span asp-validation-for="JwtToken" class="text-danger"></span> </div> <button type="submit" class="btn btn-primary">登录</button> </form>
3. 后续请求携带Bearer头的处理(非Cookie会话场景)
如果不需要服务器端Cookie会话,而是要前端主动在请求中携带Bearer头,可按以下方式处理:
- 登录成功后,将令牌存储到前端本地:
// 登录成功后执行(可在登录页CSHTML中添加) localStorage.setItem("jwtToken", "@Model.JwtToken");
- 拦截所有请求,自动添加Authorization头:
document.addEventListener("DOMContentLoaded", () => { const originalFetch = window.fetch; window.fetch = (resource, options) => { const token = localStorage.getItem("jwtToken"); if (token) { options = options || {}; options.headers = options.headers || {}; options.headers["Authorization"] = `Bearer ${token}`; } return originalFetch(resource, options); }; });
注意事项
- Razor Pages作为服务器端应用,使用Cookie认证维持会话更便捷,无需前端手动处理令牌
- 若应用包含API接口,可通过
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]指定接口使用JWT验证 - 签名密钥必须与可信系统完全一致,否则令牌验证会失败
- Cookie过期时间建议与JWT令牌的过期时间保持同步
内容的提问来源于stack exchange,提问作者Mehdi
相关产品推荐
相关产品推荐

