JWT(JSON Web Token)是一种轻量级的、基于 JSON 的开放标准(RFC 7519),用于在各方之间安全地传递信息。JWT 的特点是结构简单、轻量化和跨平台支持,适用于用户身份验证、信息加密以及无状态的 API 访问控制。使用 JWT,可以有效实现无状态的用户认证和授权,简化 Web 和 API 的身份管理流程。
一、JWT 的组成
JWT 由三部分组成,用 . 分隔:
- Header(头部):描述令牌类型和签名算法。
- Payload(负载):包含声明(Claims),如用户 ID、过期时间等。
- Signature(签名):用来验证信息的真实性。
示例 JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- Header: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
- Payload: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
- Signature: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
JWT 的应用场景
- 用户身份认证:前后端分离项目中,前端通过 JWT 验证用户身份。
- 授权:基于角色的访问控制。
- 信息传递:传递加密信息。
二、使用 JWT
使用 PyJWT 模块来生成和解析 JWT。安装方法如下:
pip install PyJWT
1. 基本用法
首先,我们来看下它的逻辑
生成 JWT
import jwt
import datetime
# 密钥
SECRET_KEY = 'mysecretkey'
# 创建 JWT
def create_token(data):
payload = {
"data": data,
"exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1) # 1小时后过期
}
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
return token
# 示例
token = create_token({"user_id": 123})print("Generated Token:", token)
解码 JWT
# 解码 JWT
def decode_token(token):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
return payload
except jwt.ExpiredSignatureError:
return "Token has expired"
except jwt.InvalidTokenError:
return "Invalid token"
# 示例
decoded = decode_token(token)print("Decoded Payload:", decoded)
2. 添加更多字段到 Payload
# 创建带有角色信息的 JWT
def create_token_with_roles(data, roles):
payload = {
"data": data,
"roles": roles,
"iat": datetime.datetime.utcnow(), # 签发时间
"exp": datetime.datetime.utcnow() + datetime.timedelta(hours=2) # 过期时间
}
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
return token
# 示例
token_with_roles = create_token_with_roles({"user_id": 456}, ["admin", "editor"])print("Token with roles:", token_with_roles)
# 解码并解析角色
decoded_with_roles = decode_token(token_with_roles)print("Decoded with roles:", decoded_with_roles)
3. 使用 Refresh Token 实现 Token 刷新
为了增强安全性,通常使用 Access Token 和 Refresh Token 的双令牌机制。
# 生成 Refresh Token
def create_refresh_token(data):
payload = {
"data": data,
"exp": datetime.datetime.utcnow() + datetime.timedelta(days=7) # 7天后过期
}
refresh_token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
return refresh_token
# 刷新 Access Token
def refresh_access_token(refresh_token):
try:
payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=["HS256"])
new_access_token = create_token(payload["data"])
return new_access_token
except jwt.ExpiredSignatureError:
return "Refresh token has expired"
except jwt.InvalidTokenError:
return "Invalid refresh token"
# 示例
refresh_token = create_refresh_token({"user_id": 123})print("Refresh Token:", refresh_token)
new_access_token = refresh_access_token(refresh_token)print("New Access Token:", new_access_token)
4. 自定义异常处理
使用 JWT 时需要处理多种可能的异常。
# 自定义异常处理函数
def decode_token_with_exceptions(token):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
return payload
except jwt.ExpiredSignatureError:
raise Exception("Token expired. Please log in again.")
except jwt.InvalidSignatureError:
raise Exception("Invalid token signature. Token might be tampered.")
except jwt.InvalidTokenError:
raise Exception("Invalid token. Please provide a valid token.")
# 示例
try:
decoded_payload = decode_token_with_exceptions(token)
print("Decoded:", decoded_payload)
except Exception as e:
print("Error:", e)
5. 实战:在 Django 中使用 JWT
安装依赖
pip install djangorestframework-simplejwt
配置 SimpleJWT
在 Django 的 settings.py 中添加配置:
INSTALLED_APPS += ["rest_framework"]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
添加视图
from rest_framework_simplejwt.views
import TokenObtainPairView, TokenRefreshView
urlpatterns = [
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
测试
- 获取 Token: POST 请求到 /api/token/,发送用户名和密码。
- 刷新 Token: POST 请求到 /api/token/refresh/,发送 refresh token。
三、注意事项
- 安全性:不要将敏感信息存储在 JWT 中。
- Token 过期策略:确保及时设置过期时间,防止长期有效的令牌带来的安全问题。
- 签名保护:使用安全的密钥存储和强加密算法。