游乐游手机版
首页/前端开发/文章详情

JWT身份验证与授权实战教程

时间:2026-06-13 06:48
JWT由Header、Payload、Signature三部分组成,用于前后端分离架构的认证。实战步骤包括安装JwtBearer包、创建登录接口生成Token、配置中间件自动验证Token、通过RequireAuthorization实现普通访问与角色权限保护。需注意HTTPS传输、不存储敏感信息、设置合理有效期及安全密钥管理。

一、前言:给 API 装个“门禁卡”

在前后端分离的架构中,JWT(JSON Web Token) 已经成为目前最主流的认证方案之一。它本质上就像一张“电子门禁卡”——用户登录成功后,服务器发给他一张卡(Token),后续每次请求都得带着这张卡。服务器只需要验证卡的真伪就行,不用每次去查数据库。这种机制既高效又简洁,可以说是现代 API 安全的基石。

二、JWT 到底是什么?

其实不用把 JWT 想得太复杂,只需搞懂三个核心部分:

  1. Header(头):声明了这张卡的类型以及用的加密算法。
  2. Payload(载荷)重点在这里。它存放着用户信息,比如用户 ID、用户名、角色等。必须注意的是,这里的数据只是 Base64 编码,千万别把密码存进去
  3. Signature(签名)这才是安全的关键。服务器用只有自己知道的密钥,对前两部分进行签名。一旦有人篡改了 Payload,签名就会对不上,服务器会直接拒绝。

三、实战准备:安装 NuGet 包

动手之前,先要在项目里安装对应的 NuGet 包:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

这个包会引入处理 JWT 验证的核心中间件,是后续所有操作的基础。

四、第一步:打造“发卡处”

用户登录时,系统需要核实账号密码,然后生成 Token 发给他。为了演示方便,我们不妨假设有一个模拟的用户库。

4.1 定义配置模型和模拟用户

Program.cs 顶部加上模型定义:

// 定义用户模型
public class User
{
    public string Username { get; set; }
    public string Password { get; set; }   // 实际项目中应存储哈希值
    public string Role { get; set; }      // 角色:Admin, User
}// 模拟数据库用户
public static class UserStore
{
    public static List Users = new List
    {
        new User { Username = "admin", Password = "123456", Role = "Admin" },
        new User { Username = "gangzi", Password = "123456", Role = "User" }
    };
}

4.2 编写登录接口

这个接口就是“发卡处”的核心逻辑。

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;// ... builder 配置 ...app.MapPost("/login", (User login) =>
{
    // 1. 验证账号密码
    var user = UserStore.Users.FirstOrDefault(u => u.Username == login.Username && u.Password == login.Password);
    if (user == null)
    {
        return Results.Unauthorized();   // 401 未授权
    }    // 2. 创建 Claims(声明)—— 也就是 Payload 里要存的数据
    var claims = new List
    {
        new Claim(ClaimTypes.Name, user.Username),
        new Claim(ClaimTypes.Role, user.Role),     // 存入角色,用于授权
        new Claim("MyCustomClaim", "SomeData")  // 也可以存自定义数据
    };    // 3. 生成签名密钥(实际项目中应从 appsettings.json 读取)
    // 密钥至少要 16 个字符
    var secretKey = "This_Is_A_Very_Secret_Key_For_JWT_2026!";
    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);    // 4. 生成 Token
    var token = new JwtSecurityToken(
        issuer: "MyTodoApp",                    // 签发者
        audience: "MyTodoAppUsers",              // 接收者
        claims: claims,
        expires: DateTime.Now.AddHours(1),     // 过期时间:1小时
        signingCredentials: creds
    );    var tokenString = new JwtSecurityTokenHandler().WriteToken(token);    return Results.Ok(new { Token = tokenString });
});

这里需要特别提醒:代码中的 secretKey 是服务器的“底牌”,一旦泄露,黑客就能伪造任意用户的 Token。所以生产环境中,一定要放在 appsettings.json 或环境变量里,而且长度要足够长。

五、第二步:配置“安检门”

有了发卡逻辑之后,还要配置中间件,让系统自动验证每个请求带来的 Token。

5.1 注册认证与授权服务

Program.csbuilder.Services 部分添加以下配置:

// 注册认证服务
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    // 配置 Token 验证参数
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        
        ValidIssuer = "MyTodoApp",
        ValidAudience = "MyTodoAppUsers",
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("This_Is_A_Very_Secret_Key_For_JWT_2026!"))
    };
});// 注册授权服务
builder.Services.AddAuthorization();

5.2 启用中间件

别忘了在 app.Build() 之后,按正确顺序调用中间件:UseAuthentication 必须在 UseAuthorization 之前。

var app = builder.Build();app.UseAuthentication();  // 开启认证:识别身份
app.UseAuthorization();   // 开启授权:检查权限// ... 其他中间件 ...

六、第三步:保护你的 API

现在“安检门”已经装好了,我们给之前的 Todo 接口加上“锁”。

6.1 普通保护:登录才能访问

在 Minimal API 中,使用 RequireAuthorization() 扩展方法,就能实现对未登录用户的拦截。

// 只有带了有效 Token 才能访问
app.MapGet("/todos", async (AppDbContext db) =>
{
    return await db.Todos.ToListAsync();
}).RequireAuthorization();

6.2 角色保护:管理员才能删除

假设删除操作只有 "Admin" 角色才能执行。但这里有一个容易踩的坑:直接传字符串是不行的。

// 错误写法:
app.MapDelete("/todos/{id}", async (int id, AppDbContext db) =>
{
    // ... 删除逻辑 ...
}).RequireAuthorization("Admin");// 正确写法:定义一个策略,或者使用 Claims
app.MapDelete("/todos/{id}", async (int id, AppDbContext db) =>
{
    // ... 删除逻辑 ...
}).RequireAuthorization(policy => policy.RequireRole("Admin"));

七、实战测试:完整流程演示

理论说完了,我们用 Postman 或 Swagger 实际跑一遍流程,看看效果。

场景一:未登录直接访问

  • 访问 GET /todos
  • 结果:401 Unauthorized。系统直接拒绝访问,门禁生效。

场景二:登录获取 Token

  • 访问 POST /login,Body 传入 {"username": "admin", "password": "123456"}
  • 结果:返回一个 JSON,里面包含了 Token 字符串。

场景三:携带 Token 访问

  1. 复制刚才的 Token。
  2. 在请求头中添加:Authorization: Bearer <你的Token>(注意 Bearer 后面有个空格)。
  3. 再次访问 GET /todos
  4. 结果:200 OK,成功返回数据!

场景四:权限不足

  1. gangzi 用户登录(角色是 User)。
  2. 携带 Token 访问 DELETE /todos/1
  3. 结果:403 Forbidden。虽然登录了,但权限不够,无法执行操作。

八、安全避坑指南

  1. HTTPS 是必须的:JWT 本身并不加密,Token 在网络传输中如果被截获,黑客就能冒充用户。唯一的防线就是 HTTPS 加密传输。
  2. 不要存敏感信息:Payload 任何人都能解码看到,千万别把密码、身份证号放进去。
  3. Token 有效期要合理:一般设置 2 小时左右比较合适。如果追求更好的用户体验,可以配合“Refresh Token”(刷新令牌)机制,这属于进阶话题,此处不展开。
  4. 密钥管理要规范:不要把密钥硬编码在代码里。建议迁移到 appsettings.jsonJwt:Key 配置项中,并通过 IConfiguration 读取。

九、总结

到这里,整个安全闭环算是完整了:

  1. 我们理解了 JWT 的原理——Header、Payload、Signature 三部分协同工作。
  2. 实现了 /login 接口负责颁发 Token。
  3. 配置了中间件对每个请求自动验证 Token。
  4. 学会了使用 RequireAuthorization 以及基于角色的权限控制。
来源:https://juejin.cn/post/7646938869473427491
上一篇TypeScript三斜线指令从入门到理解为何不再需要 下一篇前端项目如何用Vibe Coding提升开发效率
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Layui弹出层监听子页面键盘快捷键实现方法
前端开发 · 2026-07-06

Layui弹出层监听子页面键盘快捷键实现方法

子页面键盘事件监听需在DOM加载完成后绑定,父页无法直接监听子页按键,必须由子页自身监听后通过parent或postMessage通知父页。典型写法为子页调用父页已定义的关闭函数。需注意焦点状态、输入法及layui版本兼容性等陷阱。

Layui表单提交时携带当前页面Meta信息的实现方法
前端开发 · 2026-07-06

Layui表单提交时携带当前页面Meta信息的实现方法

Layui表单提交不会自动携带页面Meta信息,需在form on( submit )回调中手动读取meta内容并拼接到表单数据,注意后端字段映射及特殊字符编码,多meta时按需选取。

HTML5拖拽事件流状态转移监控调试
前端开发 · 2026-07-06

HTML5拖拽事件流状态转移监控调试

HTML5拖拽事件流易因漏监听或未调用preventDefault而中断。需掌握dragstart设置数据、dragover接受放置、drop触发条件等关键点。通过统一日志捕获事件上下文、识别常见状态丢失场景并配合可视化面板,可清晰定位拖拽过程断点。

uni-app实现小红书商品详情图卡片切换
前端开发 · 2026-07-06

uni-app实现小红书商品详情图卡片切换

通过手写touch事件与transform控制五张卡片,动态计算translateX、scale、opacity及z-index模拟层叠滑动效果。滑动距离超过80rpx触发切换,否则复位。图片仅渲染当前及前后两张,有效优化加载性能与渲染效率。

图像旋转倾斜与扭曲的Canvas像素矩阵变换
前端开发 · 2026-07-06

图像旋转倾斜与扭曲的Canvas像素矩阵变换

Canvas图像变形本质是操作坐标系,图像被动跟随。旋转需先平移原点至目标中心再旋转后复位;倾斜通过仿射变换矩阵实现;扭曲无原生API,可用分块模拟或转用WebGL。每次变换前保存状态,完成后恢复,避免坐标系偏移。