JWT是什么?JWT Token结构、解析与使用完整指南
在Web应用开发中,用户登录、接口授权和身份认证是非常常见的需求。
尤其是在前后端分离、微服务和移动端应用中,服务器通常不会在每一次请求中重新要求用户输入账号和密码,而是通过Token保存用户的认证状态。
JWT就是目前比较常见的一种Token格式。
JWT可以用于:
- 用户登录认证
- API接口授权
- 前后端身份认证
- 微服务之间的身份传递
- 单点登录
- 移动端登录
- 第三方系统接口认证
一个典型的JWT认证过程如下:
用户登录
↓
提交用户名和密码
↓
服务器验证身份
↓
生成JWT Token
↓
返回Token
↓
客户端保存Token
↓
后续请求携带Token
↓
服务器验证Token
↓
允许访问接口
本文将详细介绍JWT是什么、JWT的结构、Header和Payload分别保存什么信息、Signature有什么作用,以及JWT在实际项目中的使用方式和安全注意事项。
什么是JWT?
JWT全称:
JSON Web Token
JWT是一种开放标准定义的紧凑型Token格式,常用于在不同系统之间安全地传递声明信息。
JWT本身是一种数据格式,并不是一种加密算法。
JWT最常见的用途是:
在客户端和服务器之间传递经过签名验证的身份信息。
例如用户登录成功以后,服务器可以生成一个JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxx.yyy
客户端在之后访问需要认证的接口时,将这个Token发送给服务器。
服务器收到Token以后,可以验证:
- Token格式是否正确
- 签名是否正确
- 是否已经过期
- 是否满足其他认证条件
验证通过以后,服务器才允许用户访问对应资源。
JWT主要应用在哪些场景?
JWT在Web开发中有很多应用场景。
1. 用户登录认证
用户输入:
用户名
密码
服务器验证成功后生成JWT。
之后客户端携带JWT访问需要登录的接口。
2. API接口认证
例如:
GET /api/user/profile
客户端发送:
Authorization: Bearer <JWT>
服务器验证Token以后返回用户信息。
3. 前后端分离项目
在Vue、React、Nuxt等前端项目中,前端和后端通常是独立部署的。
这时可以使用JWT进行身份认证:
浏览器
↓
前端应用
↓
JWT
↓
后端API
4. 微服务认证
在微服务架构中,一个用户请求可能需要经过:
前端
↓
API Gateway
↓
用户服务
↓
订单服务
↓
支付服务
JWT可以作为用户身份信息在不同服务之间传递。
5. 单点登录
多个系统可以使用统一的认证中心。
例如:
统一登录中心
↓
JWT
↙ ↓ ↘
系统A 系统B 系统C
用户登录一次后,可以访问多个相关系统。
JWT长什么样?
一个典型的JWT通常类似:
xxxxx.yyyyy.zzzzz
JWT由三个部分组成:
Header.Payload.Signature
也就是:
Header
.
Payload
.
Signature
三个部分通过.连接。
例如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTYiLCJleHAiOjE3MjAwMDAwMDB9
.
xxxxx
因此:
JWT由Header、Payload和Signature三个部分组成。
JWT的三个组成部分
JWT结构可以表示为:
JWT
│
├── Header
│
├── Payload
│
└── Signature
三个部分之间使用.连接:
Header.Payload.Signature
其中:
- Header保存Token类型和签名算法
- Payload保存声明信息
- Signature用于验证Token是否被修改
什么是JWT Header?
Header通常用于保存JWT的基本信息。
例如:
{
"alg": "HS256",
"typ": "JWT"
}
常见字段包括:
| 字段 | 含义 |
|---|---|
| alg | 签名算法 |
| typ | Token类型 |
其中:
alg
表示使用什么算法进行签名。
例如:
HS256
RS256
ES256
而:
typ
通常表示:
JWT
什么是JWT Payload?
Payload是JWT中保存声明信息的部分。
例如:
{
"sub": "123456",
"name": "Tom",
"role": "admin",
"iat": 1720000000,
"exp": 1720003600
}
Payload中可以保存用户身份相关的信息。
常见字段包括:
| 字段 | 含义 |
|---|---|
| iss | Token签发者 |
| sub | Token主题或用户标识 |
| aud | Token接收方 |
| exp | Token过期时间 |
| nbf | Token生效时间 |
| iat | Token签发时间 |
| jti | Token唯一标识 |
这些字段通常称为:
JWT Claims
JWT Payload可以保存密码吗?
不建议。
这是使用JWT时非常重要的一点。
JWT的Payload通常只是Base64URL编码,并不等于加密。
例如:
用户密码
不能因为放进JWT以后变成:
JWT Payload
就认为密码已经安全。
实际上,JWT Payload通常可以被解码查看。
因此不要在Payload中保存:
- 用户密码
- 银行卡密码
- API Secret
- 私钥
- 数据库密码
- 其他敏感信息
可以保存:
- 用户ID
- 用户角色
- 权限标识
- Token过期时间
- 签发时间
JWT是否加密?
这是JWT最容易被误解的地方之一。
通常情况下:
JWT默认不是加密数据。
JWT的Header和Payload通常经过Base64URL编码。
Base64URL编码并不是加密。
例如:
原始JSON
↓
Base64URL编码
↓
JWT
任何拿到JWT的人,都可以尝试解析Header和Payload。
真正用于防止Token被篡改的是:
Signature签名。
如果需要对内容进行保密,则应该使用适合的加密机制,而不能仅依赖普通JWT签名。
什么是JWT Signature?
Signature就是JWT的签名部分。
它主要用于验证:
JWT是否被非法修改。
以HMAC算法为例,可以简单理解为:
Signature =
HMAC(
Base64URL(Header)
+ "."
+ Base64URL(Payload),
Secret
)
最终:
Header.Payload.Signature
服务器收到JWT以后,会使用自己的密钥重新计算签名。
如果计算结果与Token中的Signature一致,则说明Token内容没有被修改。
JWT签名有什么作用?
假设服务器生成了:
{
"userId": 1001,
"role": "user"
}
然后生成JWT。
攻击者如果尝试把:
role=user
修改成:
role=admin
那么Payload就发生了变化。
但是攻击者没有服务器的签名密钥,因此无法生成正确的Signature。
服务器验证时就会发现:
Token内容
↓
重新计算Signature
↓
与原Signature不一致
↓
Token验证失败
因此JWT签名主要解决的是:
数据完整性和Token真实性验证。
JWT认证完整流程
JWT登录认证通常可以分成几个步骤。
第一步:用户登录
客户端提交:
POST /api/login
Content-Type: application/json
请求:
{
"username": "tom",
"password": "123456"
}
第二步:服务器验证账号
服务器检查:
用户名
+
密码
验证成功以后生成JWT。
第三步:服务器返回Token
例如:
{
"token": "eyJhbGciOiJIUzI1NiIs..."
}
第四步:客户端保存Token
客户端可以根据应用场景选择合适的存储方式。
例如Web应用可以使用:
- HttpOnly Cookie
- 安全的客户端状态管理机制
具体选择需要结合XSS、CSRF、跨域和应用架构综合考虑。
第五步:请求接口
之后访问需要认证的接口:
GET /api/user/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
其中:
Bearer
表示后面携带的是Bearer Token。
第六步:服务器验证JWT
服务器验证:
Token格式
↓
Signature
↓
exp
↓
iss
↓
aud
↓
权限
全部满足条件后,允许访问接口。
JWT的Bearer Token是什么?
JWT经常通过HTTP Authorization请求头发送。
例如:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
其中:
Authorization
是HTTP请求头。
而:
Bearer
表示认证方案。
最后才是实际的Token。
完整结构:
Authorization: Bearer <token>
这是REST API中非常常见的JWT使用方式。
JWT如何解析?
JWT通常可以拆成三个部分:
Header.Payload.Signature
例如:
xxxxx.yyyyy.zzzzz
可以通过.分割:
const parts = token.split(".")
得到:
parts[0] → Header
parts[1] → Payload
parts[2] → Signature
Header和Payload通常可以进行Base64URL解码。
需要注意:
解码JWT并不等于验证JWT。
这是两个完全不同的概念。
JWT解析和JWT验证有什么区别?
这是开发JWT工具时非常重要的概念。
JWT解析
解析主要是:
Token
↓
Base64URL解码
↓
Header
Payload
解析只能告诉你Token里面有什么。
JWT验证
验证则需要检查:
Signature
+
算法
+
密钥
+
过期时间
+
Issuer
+
Audience
验证通过以后才能信任Token中的身份信息。
因此:
能够解析JWT,并不代表JWT是有效的。
JWT中的exp是什么?
exp表示:
Expiration Time
也就是Token过期时间。
例如:
{
"sub": "1001",
"exp": 1720003600
}
exp通常使用Unix时间戳表示。
服务器验证Token时会判断:
当前时间 > exp
如果成立,则表示:
Token已经过期
服务器通常应该拒绝该Token。
JWT中的iat是什么?
iat表示:
Issued At
也就是Token签发时间。
例如:
{
"iat": 1720000000
}
服务器可以通过这个字段了解Token大约是在什么时候生成的。
JWT中的iss是什么?
iss表示:
Issuer
也就是Token签发者。
例如:
{
"iss": "auth-server"
}
服务器可以通过检查iss判断Token是否来自可信的认证服务。
JWT中的aud是什么?
aud表示:
Audience
即Token的目标接收方。
例如:
{
"aud": "api-server"
}
如果服务器要求Token必须发给特定服务,就可以验证aud。
JWT中的sub是什么?
sub表示:
Subject
通常用于表示Token对应的主体。
在用户认证系统中,经常将用户ID放在这里。
例如:
{
"sub": "10001"
}
表示当前Token对应用户ID:
10001
JWT中的jti是什么?
jti表示:
JWT ID
可以用于表示JWT的唯一标识。
例如:
{
"jti": "550e8400-e29b-41d4-a716-446655440000"
}
在一些系统中可以利用jti实现:
- Token撤销
- Token黑名单
- 防止Token重复使用
- 会话管理
JWT常见签名算法
JWT可以使用不同的签名算法。
常见算法包括:
| 算法 | 类型 | 特点 |
|---|---|---|
| HS256 | HMAC | 对称密钥 |
| HS384 | HMAC | 对称密钥 |
| HS512 | HMAC | 对称密钥 |
| RS256 | RSA | 非对称密钥 |
| RS384 | RSA | 非对称密钥 |
| RS512 | RSA | 非对称密钥 |
| ES256 | ECDSA | 椭圆曲线 |
HS256和RS256有什么区别?
这是实际开发中经常遇到的问题。
HS256
HS256使用:
对称密钥
签名和验证使用同一个Secret。
Secret
↓
签名
↓
JWT
↓
Secret
↓
验证
适合:
- 单体应用
- 简单API
- 同一个系统内部认证
RS256
RS256使用:
非对称密钥
通常使用:
Private Key
进行签名。
使用:
Public Key
进行验证。
结构类似:
Private Key
↓
签名
↓
JWT
↓
Public Key
↓
验证
对于多个服务或者认证中心场景,RS256通常更加方便。
JWT适合微服务吗?
JWT非常适合用于微服务架构中的身份信息传递。
例如:
认证服务
│
↓
JWT
│
┌───────┼───────┐
↓ ↓ ↓
用户服务 订单服务 商品服务
各个服务可以验证JWT。
这样就不需要每个服务都直接保存用户登录密码。
不过在微服务架构中,还需要考虑:
- Token有效期
- 密钥管理
- Token撤销
- 服务之间的信任关系
- 权限控制
JWT和Session有什么区别?
JWT和Session都可以用于身份认证,但是实现方式不同。
| 对比 | JWT | Session |
|---|---|---|
| 状态保存 | 客户端携带Token | 服务端保存Session |
| 服务端存储 | 可以无状态 | 通常需要 |
| 扩展性 | 较好 | 需要共享Session |
| Token大小 | 通常较大 | Cookie通常较小 |
| 注销 | 需要额外机制 | 相对简单 |
| 微服务 | 较方便 | 需要共享会话 |
| 数据携带 | 可以携带Claims | 通常保存Session ID |
JWT并不意味着一定比Session更安全。
具体选择应该根据项目架构和安全需求决定。
JWT和OAuth有什么区别?
JWT和OAuth并不是完全相同的概念。
JWT是一种:
Token格式。
OAuth 2.0是一种:
授权框架。
OAuth可以使用JWT作为Token格式,但并不是所有OAuth Token都是JWT。
简单理解:
JWT
↓
定义Token如何组织
OAuth
↓
定义授权流程
两者解决的问题不同。
JWT常见安全问题
JWT虽然方便,但如果使用不当,也可能产生安全问题。
1. Payload保存敏感信息
不要将密码、私钥等敏感数据直接放进Payload。
因为Payload通常可以被解码。
2. Token有效期过长
如果JWT有效期设置得过长,一旦Token泄露,攻击者可能在较长时间内使用该Token。
因此应该根据业务场景设置合理的过期时间。
3. 不验证Signature
服务器不能只解析Payload就相信用户身份。
必须验证Token签名。
4. 不验证exp
Token过期以后应该拒绝继续使用。
5. 密钥管理不安全
JWT签名密钥非常重要。
不要:
硬编码在代码中
也不要:
提交到Git仓库
应该使用:
- 环境变量
- Secret管理系统
- 密钥管理服务
JWT应该设置多长有效期?
没有一个适用于所有项目的固定时间。
一般可以根据风险选择。
例如:
高安全性场景
↓
较短Access Token
普通Web应用可以采用:
短期Access Token
+
长期Refresh Token
这样既可以减少Token长期暴露的风险,又可以改善用户体验。
什么是Refresh Token?
Refresh Token用于获取新的Access Token。
典型流程:
登录
↓
Access Token
+
Refresh Token
↓
Access Token过期
↓
使用Refresh Token
↓
获取新的Access Token
例如:
Access Token
有效期:较短
Refresh Token
有效期:较长
这样用户不需要频繁重新输入密码。
JWT退出登录怎么实现?
JWT常见的一个问题是:
Token生成以后,服务器通常不会自动保存每一个Token的状态。
因此单纯使用JWT时,服务器无法像删除Session一样立即让已经签发的Token失效。
常见解决方案包括:
- 缩短Access Token有效期
- 使用Refresh Token机制
- Token黑名单
- 保存JWT ID
- 服务端维护会话状态
- 修改用户Token版本号
具体方案需要根据安全要求选择。
JWT在前端项目中的使用方式
前端登录成功以后:
用户登录
↓
后端返回JWT
↓
前端保存认证状态
↓
请求API
↓
携带JWT
例如:
const response = await fetch("/api/user", {
headers: {
Authorization: `Bearer ${token}`
}
})
服务器收到请求以后验证Token。
JWT在后端接口中的典型流程
后端收到请求:
HTTP Request
↓
获取Authorization
↓
提取Bearer Token
↓
解析JWT
↓
验证Signature
↓
验证exp
↓
验证iss/aud
↓
获取用户身份
↓
检查权限
↓
执行业务逻辑
这也是大多数JWT认证中间件的基本工作过程。
JWT认证和权限控制有什么区别?
JWT主要解决:
你是谁?
而权限控制解决:
你能做什么?
例如JWT中:
{
"sub": "10001",
"role": "admin"
}
服务器首先验证:
Token有效吗?
然后再检查:
role是否允许访问当前接口?
所以:
身份认证
+
权限控制
是两个不同的概念。
JWT常见错误
开发JWT接口时经常会遇到以下问题。
401 Unauthorized
通常表示:
- Token不存在
- Token无效
- Token已经过期
- Signature验证失败
- 认证信息错误
403 Forbidden
通常表示:
用户身份已经确认,但是没有访问资源的权限。
例如:
普通用户
↓
访问管理员接口
↓
403 Forbidden
因此:
401
和:
403
含义不同。
如何判断JWT是否过期?
JWT中的exp通常保存过期时间。
解析以后:
{
"exp": 1720003600
}
将时间戳转换为日期,就可以知道Token的过期时间。
但是需要注意:
前端解析exp只能用于界面提示或提前刷新,不能代替服务器端的Token验证。
最终是否有效,必须由服务端验证。
在线JWT解析工具有什么作用?
如果开发过程中需要查看JWT内容,可以使用JWT解析工具。
例如:
通常可以查看:
- Header
- Payload
- Signature
- Token结构
- exp
- iat
- iss
- aud
- sub
这对于调试登录接口和API认证非常方便。
JWT解析工具能验证Token吗?
需要区分:
解析
和:
验证
解析JWT:
读取Header
+
读取Payload
不需要知道服务器的Secret。
而验证JWT签名:
Header
+
Payload
+
Secret / Public Key
才能判断签名是否有效。
因此,普通的在线JWT解析功能并不代表可以验证Token的真实性。
使用JWT时的安全建议
在实际项目中使用JWT,可以遵循以下原则:
- 不要在Payload中保存密码。
- 不要将Secret提交到Git仓库。
- 使用HTTPS传输Token。
- 设置合理的Token过期时间。
- 服务端必须验证Signature。
- 服务端必须检查Token是否过期。
- 根据场景验证iss和aud。
- 对权限进行单独校验。
- 对高风险系统考虑Refresh Token机制。
- 对敏感操作增加额外认证。
- 妥善管理签名密钥。
- Token泄露后应具备撤销或失效机制。
JWT与HTTPS有什么关系?
JWT签名可以防止Token内容被篡改,但JWT本身通常不会隐藏Payload内容。
因此:
JWT签名
主要解决:
防篡改和完整性验证。
而:
HTTPS
主要用于:
保护网络传输过程。
两者解决的问题不同。
实际Web应用中通常应该:
HTTPS
+
JWT
+
合理的Token有效期
+
服务端签名验证
共同构成完整的认证方案。
JWT使用流程总结
一个完整的JWT登录流程可以概括为:
用户
↓
输入账号密码
↓
登录接口
↓
服务器验证身份
↓
生成JWT
↓
返回客户端
↓
客户端保存认证状态
↓
访问API
↓
Authorization: Bearer Token
↓
服务器验证JWT
↓
验证Signature
↓
验证Token有效期
↓
验证权限
↓
返回数据
JWT和普通Token有什么区别?
普通Token可以只是一个随机字符串:
a8f91c2d7e...
服务器需要根据Token查询对应的用户信息。
JWT则可以在Token中携带Claims:
Header
+
Payload
+
Signature
因此JWT具有结构化、自包含等特点。
但是这并不意味着JWT一定比普通Token更适合所有系统。
如果系统需要随时撤销Token,或者服务端必须完全控制会话状态,传统Session或随机Token方案也可能更加合适。
总结
JWT(JSON Web Token)是一种常见的Token格式,广泛用于:
- 用户登录
- API认证
- 前后端分离
- 微服务
- 单点登录
- 身份授权
JWT由三个部分组成:
Header.Payload.Signature
其中:
Header
保存Token类型和签名算法。
Payload
保存用户身份和其他Claims。
Signature
用于验证Token是否被修改以及是否由可信的一方签发。
需要特别注意:
JWT的Payload通常不是加密数据,不能把密码等敏感信息直接放进去。
在实际项目中,JWT应该结合HTTPS、合理的Token有效期、密钥管理、权限控制以及必要的Refresh Token机制一起使用。
如果只是需要查看一个JWT里面包含哪些信息,可以使用:
如果需要进一步处理Hash、MD5或SHA等安全相关数据,也可以使用:
JWT的核心并不只是“生成一个Token”,真正重要的是建立一套完整的:
身份认证
+
Token验证
+
权限控制
+
过期管理
+
安全防护
机制。