前言
在前后端分离和微服务架构盛行的当下,安全高效的身份验证与授权机制是保障系统稳定运行的关键。JSON Web Token(JWT)作为一种开放标准(RFC 7519),以简洁、自包含的特性,成为众多开发者实现无状态身份验证的首选方案。Spring Boot 凭借其快速开发的优势,与 JWT 的整合能大幅提升项目的安全性与开发效率。本文将深入剖析 JWT 原理,详解多种实现方式、框架优劣点、不同 Spring Boot 版本的适配差异,并提供丰富的代码示例,助力开发者掌握这一核心技术。
一、JWT 原理深度剖析
1.1 JWT 结构组成
JWT 由三部分组成,分别是Header(头部)、Payload(负载)和Signature(签名),各部分通过.分隔,形如xxx.yyy.zzz
。
- Header:包含令牌的类型(通常为JWT)和所使用的签名算法,例如:
将上述 JSON 对象进行 Base64Url 编码后,便构成了 JWT 的 Header 部分。{ "alg": "HS256", "typ": "JWT" }
- Payload:用于存放有效信息,包含声明(Claims),如用户身份、权限、过期时间等。可分为三种类型:注册声明(如
iss
- 签发者、exp
- 过期时间)、公共声明(自定义信息)和私有声明(用于双方之间共享的信息)。示例如下:
同样经过 Base64Url 编码后,成为 JWT 的 Payload 部分。{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
- Signature:用于验证消息在传递过程中是否被篡改,同时对于使用私钥签名的情况,还能验证 JWT 的发送者身份是否有效。签名的生成需要使用编码后的 Header、编码后的 Payload、一个密钥(只有服务器知道)以及 Header 中指定的签名算法。例如,使用 HMAC SHA256 算法时,签名的计算方式为:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
1.2 JWT 工作流程
- 用户向服务器发送用户名和密码进行登录请求。
- 服务器验证用户凭据,如果验证通过,根据用户信息生成包含必要声明的 JWT,并将其返回给客户端。
- 客户端收到 JWT 后,通常会将其存储在
localStorage、session
Storage或cookie
中。 - 后续客户端向服务器发起受保护资源的请求时,会在请求头的
Authorization
字段中携带 JWT,格式为Bearer <token>
。 - 服务器接收到请求后,从请求头中提取 JWT,并使用与生成时相同的密钥和算法对其进行验证。若验证通过,解析 JWT 中的 Payload 获取用户信息,进而处理请求;若验证失败,则拒绝请求。
1.3 JWT 的优势与局限
- 优势:自包含信息,无需频繁查询数据库;简洁轻便,便于在 HTTP 请求中传输;跨语言、跨平台兼容性强;支持多种签名算法,安全性较高。
- 局限:Payload 中的信息是公开的(虽经过编码但可解码),不适合存放敏感数据;令牌一旦签发,在过期前无法主动失效,若泄露可能造成安全风险;不适合存储大量数据,因为会增加 HTTP 请求的大小。
二、Spring Boot 整合 JWT 多种实现方式
2.1 基于 JJWT 库的基础实现
2.1.1 项目搭建与依赖添加
创建 Spring Boot 项目,在pom.xml
文件中添加 JJWT 库依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
2.1.2 JWT 工具类编写
创建JwtUtil
工具类,用于生成和验证 JWT:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken