当前位置: 首页 > news >正文

SpringBoot--JWT

一、JWT 的简单了解

1. 什么是 JWT?

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在 各方之间安全地传输信息。它基于 JSON 格式,信息通过 数字签名 的方式保证不可篡改,常用于 身份认证和信息交换


2. JWT 的结构

JWT 由三部分组成,每部分用 . 分隔:

Header.Payload.Signature

(1) Header(头部)

描述 类型签名算法。例如:

{"alg": "HS256","typ": "JWT"
}

Base64Url 编码后得到第一部分。


(2) Payload(载荷)

存放 声明(Claims) 的地方。
声明分三类:

  • 注册声明(Registered Claims):建议但非必须使用的标准字段

    • iss:签发者 (issuer)

    • sub:主题 (subject)

    • aud:接收者 (audience)

    • exp:过期时间 (expiration time)

    • nbf:生效时间 (not before)

    • iat:签发时间 (issued at)

    • jti:JWT ID,用于防止重放攻击

  • 公共声明(Public Claims):大家约定好的字段

  • 私有声明(Private Claims):系统内部定义的字段,比如 userIdrole

例如:

{"sub": "user123","name": "Alice","role": "admin","exp": 1692345600
}

Base64Url 编码后得到第二部分。


(3) Signature(签名)

用于防篡改。
计算方法:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret
)

即:把前两部分拼接,用密钥和算法加密生成签名。


3. JWT 的认证流程

  1. 用户登录:客户端提交用户名、密码。

  2. 服务端验证:验证通过后,生成 JWT(带用户信息、过期时间等),返回给客户端。

  3. 客户端存储:通常存储在 LocalStorage 或 Cookie 中。

  4. 后续请求:客户端请求时在 Header 中带上 Authorization: Bearer <token>

  5. 服务端验证:服务端用密钥验证 JWT 是否有效、是否过期、是否被篡改。

  6. 验证通过:允许访问资源。


4. JWT 的优点

  • 无状态:服务端不存储 Session,支持分布式扩展。

  • 跨语言:JSON 格式,兼容性强。

  • 高性能:减少数据库查询,认证速度快。

  • 信息完整:载荷可携带用户信息,减少额外查询。


5. JWT 的缺点

  • 不可撤销:一旦签发,在过期前无法主动让其失效(除非维护黑名单)。

  • 体积较大:比 Session ID 更大(因为要携带签名和用户信息)。

  • 安全风险:如果私钥泄露,所有 token 都会失效。

   5.1 为什么说不可撤销呢?在前端删除jwt(前端销毁)不就好了?

         用户自己点击 “退出登录”,前端删除 token,下次再访问接口时就没有 token 了 → 确实相当于退出了

         在大多数 正常用户行为 下,这种方式足够。

 5.1.1 但是会有特殊情况:

(1)多端登录 / 被动下线🔹如果一个账号在两台设备登录,管理员希望强制其中一台下线。🔹单靠前端删 token,另一台设备的 token 依然有效。(2)token 泄露🔹假如 token 被别人拷贝了(比如被窃取、抓包、XSS 攻击),那个人依然可以继续用。🔹你本地删掉 token 没用,因为“坏人”还有副本。(3)黑名单/封禁需求🔹如果公司后台管理员封禁了某个账号,这个用户的 token 在过期前仍然能请求接口。🔹只能靠服务端来控制 token 的立即失效。

    5.2 解决办法:

        具体实现本文不做演示,着重介绍JWT

  • 前端销毁:保证用户主动退出后,浏览器不再携带 token。

  • 后端控制:保证遇到异常场景(黑名单、泄露、多端冲突)时,能强制失效。

    • 方式一:Redis 黑名单

    • 方式二:Redis 白名单(只保留最新 token)

    • 方式三:短 token + refresh token


6. 使用场景

  • 用户认证(替代传统 session)。

  • API 鉴权(前后端分离、微服务)。

  • 信息安全传输(声明不可篡改)。


二、Spring Boot 使用 JWT 的完整示例

这里我们用 jjwt 库(io.jsonwebtoken:jjwt-api)来实现。


1. 添加依赖(Maven)

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.5</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.5</version><scope>runtime</scope>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId> <!-- 支持 json 序列化 --><version>0.11.5</version><scope>runtime</scope>
</dependency>

2. 工具类 JwtUtil

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;import java.security.Key;
import java.util.Date;public class JwtUtil {// 私钥(实际项目中放到配置文件里)private static final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);// 生成 tokenpublic static String generateToken(String userId, String role) {long nowMillis = System.currentTimeMillis();long expMillis = nowMillis + 3600000; // 1小时过期Date exp = new Date(expMillis);return Jwts.builder().setSubject(userId) // sub.claim("role", role) // 自定义字段.setIssuedAt(new Date(nowMillis)) // iat.setExpiration(exp) // exp.signWith(key) // 签名.compact();}// 验证 tokenpublic static boolean validateToken(String token) {try {Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);return true;} catch (JwtException e) {return false;}}// 获取用户IDpublic static String getUserId(String token) {Claims claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();return claims.getSubject();}// 获取角色public static String getUserRole(String token) {Claims claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();return claims.get("role", String.class);}
}

3. Controller 示例

import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/auth")
public class AuthController {// 模拟登录接口@PostMapping("/login")public String login(@RequestParam String username, @RequestParam String password) {// 假设用户名=admin, 密码=123456if ("admin".equals(username) && "123456".equals(password)) {// 登录成功,生成 JWTreturn JwtUtil.generateToken("1001", "admin");}return "用户名或密码错误";}// 需要鉴权的接口@GetMapping("/check")public String check(@RequestHeader("Authorization") String token) {token = token.replace("Bearer ", "");if (JwtUtil.validateToken(token)) {return "用户ID:" + JwtUtil.getUserId(token) +",角色:" + JwtUtil.getUserRole(token);}return "token 无效或已过期";}
}

4. 请求示例

(1) 登录获取 Token

POST http://localhost:8080/auth/login?username=admin&password=123456

返回:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMDAxIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNjkyMzQ1NjAwLCJleHAiOjE2OTIzNDkyMDB9.Tk7Q7jtwgm3d...

(2) 携带 Token 访问接口

GET http://localhost:8080/auth/check
Header: Authorization: Bearer <上一步返回的token>

返回:

用户ID:1001,角色:admin

✅ 总结:

  • JWT 由 头部 + 载荷 + 签名 组成。

  • 使用时,客户端存储 token 并在请求头中传递。

  • Spring Boot 中可以通过 工具类 + 拦截器/过滤器 来实现鉴权。

http://www.dtcms.com/a/338337.html

相关文章:

  • WPF 打印报告图片大小的自适应(含完整示例与详解)
  • 初识CNN04——经典网络认识
  • 驱动开发系列64 - glCompileShader实现-GLSL 精度优化pass
  • 3.1 结构化输出(大模型的封闭与开放)
  • Windows系统上使用GIT
  • CMake指令:查找文件(find_file)、查找目录(find_path)、查找库文件(find_library)
  • Life:Internship in OnSea Day 57
  • 【Kubernetes】在 K8s 上部署 Prometheus
  • 1-Flask相关知识点
  • 恒创科技:日本服务器 ping 不通?从排查到解决的实用指南
  • 朝阳区24小时图书馆“焕新计划”启幕 文化讲座点亮夜间阅读之光
  • ST05跟踪MRP的运行(MD01)过程
  • 使用chmod 命令修改文件权限
  • 【完整源码+数据集+部署教程】空中目标检测系统源码和数据集:改进yolo11-UniRepLKNetBlock
  • mac 电脑安装类似 nvm 的工具,node 版本管理工具
  • 【机器人-基础知识】ROS2常用命令
  • Vue3 全新特性 defineModel 深度解析
  • CentOS Linux 7 (Core)上部署Oracle 11g、19C RAC详细图文教程
  • 【MySQL】超详细入门学习
  • vue3 + antd modal弹窗拖拽全局封装 使用useDraggable
  • LeetCode100 -- Day1
  • 嵌入式工程师常去的网址
  • 缺陷检测最新综述:针对现实世界工业缺陷检测的综合调查:挑战、方法与展望
  • C++对象的内存布局
  • 拓扑排序详解:从力扣 207 题看有向图环检测
  • 2025年最新美区Apple ID共享账号免费分享(持续更新)
  • 决策树(1)
  • 2025年秋招Java后端面试场景题+八股文题目
  • pandas基本数据
  • 开疆智能Profient转EtherCAT网关连接伦茨变频器配置案例