JWT令牌技术
一、JWT令牌的定义
JWT(JSON Web Token)是一种基于JSON的开放标准(RFC 7519),用于在网络应用间安全传递声明信息。其核心特点是通过数字签名或加密实现数据的自包含性和防篡改,无需依赖中心化存储即可完成身份验证。
核心特性
自包含性:令牌内直接携带用户身份、权限等关键信息,服务端无需查询数据库即可完成验证。
无状态性:适用于分布式系统,避免传统Session机制中的会话同步问题
跨域支持:通过HTTP头部传递,天然适配微服务架构和跨域资源共享(CORS)
二、JWT令牌的组成结构
JWT由三部分通过点(.)连接组成,格式为:Header.Payload.Signature
1. 头部(Header)
- 作用:声明令牌类型与签名算法。
- 编码方式:Base64URL编码
2. 载荷(Payload)
作用:存储用户身份、权限及其他自定义数据。
标准字段
(RFC定义):iss(签发者)、sub主题)、exp(过期时间)、iat(签发时间)
自定义字段:可添加业务相关数据(如userId、role),但需避免存储敏感信息(因Base64可逆解码)
3. 签名(Signature)
- 作用:验证令牌完整性,防止篡改。
- 生成方式:将Header和Payload的Base64编码字符串拼接,使用Header中指定的算法(如HS256)与密钥加密
- 验证流程:服务端通过相同算法和密钥重新计算签名,与令牌中的签名比对
三、JWT令牌的适用场景
1. 单点登录(SSO)与跨域认证
- 场景描述:用户在一个系统登录后,JWT可作为凭证在多个关联系统中复用,无需重复认证。例如,认证中心颁发JWT后,用户携带该令牌访问其他业务系统时可直接通过签名验证身份。
- 优势:避免维护复杂的Session同步机制,减少服务器存储压力,尤其适合多域名、多子系统的分布式架构。
2. 分布式系统与微服务架构
- 场景描述:在微服务间传递身份信息时,JWT无需依赖中心化Session存储,各服务可独立验证令牌有效性。例如,Kubernetes服务网格通过JWT实现服务间认证。
- 优势:无状态特性简化服务扩展,降低系统耦合度,符合云原生设计原则。
3. 移动端与API认证
- 场景描述:移动应用通过JWT实现API访问授权。客户端将令牌存储在本地(如iOS的UserDefaults或Android的SharedPreferences),每次请求携带令牌头。
- 优势:避免依赖Cookie,适配移动端网络环境,且支持跨平台(如React Native、Flutter)。
4. 无密码认证与临时授权
- 场景描述:用户通过“魔法链接”登录时,系统发送含JWT的链接至用户邮箱,点击后直接完成认证。
- 优势:提升用户体验,减少密码管理风险,适用于短期操作(如密码重置)。
5. 第三方授权(OAuth 2.0)
- 场景描述:在OAuth 2.0流程中,JWT作为访问令牌(Access Token)传递,资源服务可直接解析令牌中的权限声明,无需频繁查询授权服务器。
- 优势:降低授权服务器负载,支持细粒度权限控制(如角色、作用域)。
四、JWT令牌的不适用场景
1. 需要频繁撤销权限或令牌的场景
- 问题核心:JWT一旦签发即不可修改,若需立即撤销用户权限(如用户被封禁),只能等待令牌过期或强制刷新密钥,存在安全滞后性。
- 替代方案:使用黑名单机制(将失效令牌存入Redis)或改用Session机制实时控制权限。
2. 长时间有效的令牌需求
- 风险点:长期有效的JWT一旦泄露,攻击者可在过期前持续滥用。例如,用户离职后其令牌仍可访问敏感资源。
- 解决方案:缩短令牌有效期(如1小时),配合刷新令牌(Refresh Token)延长会话。
3. 高并发与带宽敏感场景
- 性能瓶颈:JWT体积较大(通常500B-2KB),在大量并发请求中会增加网络传输开销,影响响应速度。
- 替代方案:对带宽敏感场景(如物联网设备)改用轻量级Token(如随机UUID)。
4. 需要存储复杂用户状态的场景
- 局限性:JWT的无状态特性难以支持动态会话管理,例如需要跟踪用户在线状态、实时操作日志等。
- 适用技术:传统Session机制或数据库存储会话详情。
5. 对安全性要求极高的敏感场景
- 风险暴露:JWT默认仅签名不加密,载荷(Payload)可被Base64解码,若包含敏感信息(如用户ID、角色)易遭中间人窃取。
- 改进措施:结合JWE(JSON Web Encryption)加密载荷,或仅存储非敏感标识符。
五、JWT令牌的快速入门使用
1.maven引入jwt
1 | <!-- jwt--> |
2.创建jwt工具类,在里面创建两个方法
1 | //创建jwt令牌 |
3.创建jwt令牌
- addClaims()添加自定义内容到有效荷载(payload)中。
- signWith():指定算法和密钥生成签名。
- setExpiration():设置过期时间(System.currentTimeMillis()是返回当前的时间)
- compact():生成最终的JWT字符串
1 | private static String signKey = "luminous";//秘钥 |
4.创建jwt解析
4.1. 创建解析器实例 (Jwts.parser())
- 作用:初始化JWT解析器对象,准备进行令牌解析。
- 底层实现:返回DefaultJwtParser对象,该对象包含解码、验签等核心逻辑。内部初始化压缩解码器(如DefaultCompressionCodecResolver)和时钟校验工具(DefaultClock)。
4.2. 设置签名密钥 (setSigningKey(signKey))
- 关键作用:提供验证签名所需的密钥,确保令牌未被篡改。
- 技术要点:密钥必须与生成JWT时使用的密钥完全一致,否则验签失败。。
4.3. 解析并验证令牌 (parseClaimsJws(jwt))
执行流程:
- 拆分JWT:以.分隔符切分Header、Payload、Signature三部分,校验格式有效性。
- 解码头部:Base64URL解码Header,获取签名算法(HS256)。
- 验证签名:使用密钥重新计算签名,与JWT中的Signature比对,防止数据篡改。
异常类型:
SignatureException:签名不匹配或密钥错误。
ExpiredJwtException:令牌已过期。
MalformedJwtException:JWT格式错误(如缺少部分)。
4.4. 提取声明数据 (getBody())
- 返回值:Claims对象,本质是包含Payload数据的Map结构。
1 | //解析jwt令牌 |
5.使用jwt
只需调用对应的这两个方法就可以,创建一个测试类,先生成jwt令牌
1 | @Test |
运行结果:
由于jwt令牌太长,图片无法完全展示,我将他复制下来
eyJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6ImFkbWluIiwiaWQiOjEsInVzZXJuYW1lIjoiYWRtaW4iLCJleHAiOjE3NDgwMTE0NDF9.znQ42CQWrd_lYoSmrNF2d1x20k8RH0tMdA-Di3kmQKU
接下来我们将生成jwt的方法注释掉,运行解析jwt方法
1 | @Test |
可以看到解析出来的内容跟我们之前设置的内容是一样的。这样,就完成了jwt令牌的生成和解析。


