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

如何在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头,可按以下方式处理:

  1. 登录成功后,将令牌存储到前端本地:
// 登录成功后执行(可在登录页CSHTML中添加)
localStorage.setItem("jwtToken", "@Model.JwtToken");
  1. 拦截所有请求,自动添加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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:37:38