导读:本期聚焦于公主创作的《C#的JWT认证是什么?如何在Web API中实现Token验证?》,敬请观看详情。要实现Web API的接口访问控制,常见方案是让客户端先调用登录接口获取一个加密签名的令牌,后续请求把令牌放到Authorization头中访问受保护接口,这个令牌就是JWT。JWT由头部、载荷和签名三段组成,头部声明签名算法,载荷保存用户标识和过期时间,签名使用密钥对前两段计算得出,服务端可通过签名判断令牌是否被篡改。在ASP.NET Core里落地JWT并不复杂:安装JwtBearer包后,在Program中注册认证服务并配置TokenValidationParameters,登录接口里用JwtSecurityTokenHandler生成令牌,受保护控制器只需添加Authorize特性,中间件就会在请求进入前完成签名、有效期和签发方校验。实际项目中还要关注密钥强度、HTTPS传输、过期时间以及令牌存储位置,避免XSS和CSRF风险。

JWT(JSON Web Token)常被误解为一种加密后的用户凭证,实际上它只做签名而不做加密。令牌本身由三段Base64Url字符串拼接而成,任何拿到令牌的人都可以解开载荷部分查看内容,因此绝不能把密码或敏感身份数据直接放进JWT。理解这一点是正确实现Token验证的前提。

C#的JWT认证是什么?如何在Web API中实现Token验证?

一、JWT认证的核心机制

JWT的结构可以从一个典型令牌说起。形如 xxxxx.yyyyy.zzzzz 的字符串中,第一段是头部,声明令牌类型和签名算法,例如 HS256;第二段是载荷,存放签发方、过期时间、用户标识等声明;第三段是签名,由服务端使用密钥对前两段进行哈希计算得到。

这种设计的优势在于服务端无需保存会话状态。传统Cookie会话需要在内存或数据库中记录SessionID,而JWT把用户信息放在令牌里,服务端只要验证签名和有效期就能识别用户身份。付出的代价也很直接:令牌一旦签发,在过期之前无法主动吊销,除非引入额外的刷新令牌或黑名单机制。

签名算法选择上,HS256使用对称密钥,适合单体服务或内部系统;RS256使用非对称密钥对,私钥签发、公钥验证,更适合微服务网关与资源服务分离的场景。无论哪种算法,密钥泄露都会导致攻击者伪造令牌。

二、在ASP.NET Core Web API中签发JWT Token

要在 ASP.NET Core 项目中使用JWT认证,首先需要安装 Microsoft.AspNetCore.Authentication.JwtBearer 包。它提供中间件和默认配置,能够自动从请求的 Authorization 头中提取 Bearer Token 并完成验证。

安装完成后,在 appsettings.json 中配置密钥、签发方、接收方和过期时间。密钥长度必须足够,使用HS256时建议至少32字节,否则运行时会直接报错。接着在 Program.cs 中注册认证服务,并设置令牌验证参数。

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
        };
    });

builder.Services.AddAuthorization();

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

生成令牌通常放在登录接口里。用户提交用户名和密码后,接口先校验凭证,再构造Claims集合。这里的 Claim 是用户身份的表述,可以包含用户ID、邮箱、角色等。随后用 JwtSecurityTokenHandler 把令牌写成字符串返回给客户端。

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.Text;

[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
    private readonly IConfiguration _configuration;

    public AuthController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    [HttpPost("login")]
    public IActionResult Login(LoginRequest request)
    {
        // 这里应校验数据库中的用户密码,示例仅做说明
        if (request.Username != "admin" || request.Password != "123456")
        {
            return Unauthorized();
        }

        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, "1001"),
            new Claim(JwtRegisteredClaimNames.Email, "admin@ipipp.com"),
            new Claim(ClaimTypes.Role, "admin")
        };

        var key = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: _configuration["Jwt:Issuer"],
            audience: _configuration["Jwt:Audience"],
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(120),
            signingCredentials: creds
        );

        var tokenString = new JwtSecurityTokenHandler().WriteToken(token);

        return Ok(new { token = tokenString, expires = DateTime.UtcNow.AddMinutes(120) });
    }
}

public class LoginRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}

三、保护API控制器并验证Token

令牌返回给客户端后,后续请求需要在 HTTP 头中加入 Authorization: Bearer 令牌字符串。在控制器或具体动作上添加 [Authorize] 特性后,JwtBearer 中间件会在请求到达Action前执行验证,包括签名是否合法、令牌是否过期、签发方和接收方是否与配置一致。

验证通过的请求可以直接通过 User 对象读取声明。下面的控制器演示了获取当前用户ID和角色,并返回订单数据。使用 [AllowAnonymous] 可以让某个动作跳过认证,通常用于登录或健康检查接口。

using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;

[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
    [HttpGet]
    [Authorize]
    public IActionResult GetOrders()
    {
        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
        var email = User.FindFirstValue(ClaimTypes.Email);
        var role = User.FindFirstValue(ClaimTypes.Role);

        return Ok(new { userId, email, role, orders = new[] { "A1001", "A1002" } });
    }

    [HttpGet("public")]
    [AllowAnonymous]
    public IActionResult PublicInfo()
    {
        return Ok(new { message = "无需认证" });
    }
}

如果需要按角色或策略限制访问,可以配合 AddAuthorization 注册策略,再使用 [Authorize(Policy = "AdminOnly")] 或 [Authorize(Roles = "admin")]。角色声明需要与登录时加入的 Claim 类型一致,否则会出现认证通过但授权失败的情况。

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy => policy.RequireRole("admin"));
});

四、JWT安全实践与常见问题

安全存储是JWT落地时最容易出问题的环节。把令牌放在 localStorage 里容易受到XSS攻击,攻击者一旦注入脚本即可读取令牌并冒用身份。更稳妥的做法是将令牌放入 HttpOnly Cookie,前端代码无法读取,能显著降低XSS导致的凭证泄露风险,但需要配合CSRF防护。移动端没有Cookie机制,通常将令牌保存在系统安全存储中。

另一个常见问题是密钥管理。开发环境里把密钥写死在配置文件中虽然方便,但生产环境应使用环境变量、密钥管理服务或配置中心注入。如果使用对称签名,密钥必须足够长且定期轮换;轮换时旧令牌会快速失效,需要设计合理的过渡策略。

过期时间设置也需要平衡。过期太短用户体验差,过期太长风险窗口大。一般可以将访问令牌设为15分钟到2小时,同时使用刷新令牌延长登录周期。刷新令牌更敏感,应当只发送给认证服务,并保存在服务端或安全存储中。JWT本身无法凭空吊销,需要黑名单或版本号机制应对用户退出、改密等场景。

最后注意传输安全。Authorization头中的令牌如果不走HTTPS,可能被中间人截获。测试时不要把真实密钥提交到代码仓库,也不要打印完整令牌到日志。Web API 应统一在网关或应用层强制HTTPS,从源头上减少泄露面。

JWT认证ASP.NET CoreToken验证修改时间:2026-09-21 16:02:53

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0921/60117.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。