|
| 1 | +### **JWT(JSON Web Token)详解** |
| 2 | + |
| 3 | +#### **1. 什么是 JWT?** |
| 4 | + |
| 5 | +JWT(JSON Web Token)是一种用于 **身份验证(Authentication)** 和 **信息安全传输** 的开放标准(RFC 7519)。它通过 JSON 形式存储声明信息(claims),并使用 **数字签名** 保证数据完整性。 |
| 6 | + |
| 7 | +JWT 主要用于: |
| 8 | + |
| 9 | ++ **用户身份验证**(如 OAuth 授权) |
| 10 | ++ **API 认证**(如 RESTful API 访问) |
| 11 | ++ **信息安全传输**(如在微服务间传递认证信息) |
| 12 | + |
| 13 | +--- |
| 14 | + |
| 15 | +#### **2. JWT 的结构** |
| 16 | + |
| 17 | +JWT 由 **三部分** 组成,每部分之间用 `.` 分隔: |
| 18 | + |
| 19 | +```plain |
| 20 | +Header.Payload.Signature |
| 21 | +``` |
| 22 | + |
| 23 | +这三部分分别是: |
| 24 | + |
| 25 | ++ **Header(头部)**:说明使用的算法和 token 类型 |
| 26 | ++ **Payload(载荷)**:存储用户信息和声明(Claims) |
| 27 | ++ **Signature(签名)**:用于验证 JWT 的真实性 |
| 28 | + |
| 29 | +##### **示例 JWT** |
| 30 | + |
| 31 | +```plain |
| 32 | +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInJvbGUiOiJhZG1pbiIsImlhdCI6MTY5MTMwNjgwMCwiZXhwIjoxNjkxMzEwNDAwfQ.OjR1mI5fBItMdXsH2fF2p5Aj54PkbOSmCFEwC_Qw1tE |
| 33 | +``` |
| 34 | + |
| 35 | +**分解后:** |
| 36 | + |
| 37 | +1. **Header(Base64编码)** |
| 38 | + |
| 39 | +```json |
| 40 | +{ |
| 41 | + "alg": "HS256", |
| 42 | + "typ": "JWT" |
| 43 | +} |
| 44 | +``` |
| 45 | + |
| 46 | +2. **Payload(Base64编码)** |
| 47 | + |
| 48 | +```json |
| 49 | +{ |
| 50 | + "user_id": 123, |
| 51 | + "role": "admin", |
| 52 | + "iat": 1691306800, |
| 53 | + "exp": 1691310400 |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +3. **Signature(HMAC SHA256 计算)** |
| 58 | + |
| 59 | +```python |
| 60 | +HMACSHA256( |
| 61 | + base64UrlEncode(header) + "." + |
| 62 | + base64UrlEncode(payload), |
| 63 | + secret |
| 64 | +) |
| 65 | +``` |
| 66 | + |
| 67 | +--- |
| 68 | + |
| 69 | +#### **3. JWT 如何工作?** |
| 70 | + |
| 71 | +1. **用户登录** |
| 72 | + - 用户使用账号密码登录,服务器验证成功后生成 JWT 并返回给用户。 |
| 73 | +2. **用户请求 API** |
| 74 | + - 之后,用户每次请求 API 时,都在 `Authorization` 头中携带 `Bearer <JWT>` 访问受保护资源。 |
| 75 | +3. **服务器验证 JWT** |
| 76 | + - 服务器端使用 **签名密钥** 解析 JWT,验证合法性,并检查 `exp` 是否过期。 |
| 77 | + |
| 78 | +--- |
| 79 | + |
| 80 | +### **4. Python 实现 JWT** |
| 81 | + |
| 82 | +Python 中可以使用 `PyJWT` 进行 JWT 生成和解析。 |
| 83 | + |
| 84 | +#### **4.1 安装 **`PyJWT` |
| 85 | + |
| 86 | +```bash |
| 87 | +pip install PyJWT |
| 88 | +``` |
| 89 | + |
| 90 | +#### **4.2 生成 JWT** |
| 91 | + |
| 92 | +```python |
| 93 | +import jwt |
| 94 | +import datetime |
| 95 | + |
| 96 | +# 定义密钥(务必妥善保存) |
| 97 | +SECRET_KEY = "mysecretkey" |
| 98 | + |
| 99 | +# 生成 Token |
| 100 | +def create_jwt(user_id: int, role: str): |
| 101 | + payload = { |
| 102 | + "user_id": user_id, |
| 103 | + "role": role, |
| 104 | + "iat": datetime.datetime.utcnow(), |
| 105 | + "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1) # 1小时后过期 |
| 106 | + } |
| 107 | + |
| 108 | + token = jwt.encode(payload, SECRET_KEY, algorithm="HS256") |
| 109 | + return token |
| 110 | + |
| 111 | +# 示例 |
| 112 | +token = create_jwt(123, "admin") |
| 113 | +print("JWT Token:", token) |
| 114 | +``` |
| 115 | + |
| 116 | +--- |
| 117 | + |
| 118 | +#### **4.3 解析 JWT** |
| 119 | + |
| 120 | +```python |
| 121 | +def decode_jwt(token: str): |
| 122 | + try: |
| 123 | + decoded_payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"]) |
| 124 | + return decoded_payload |
| 125 | + except jwt.ExpiredSignatureError: |
| 126 | + return "Token 已过期" |
| 127 | + except jwt.InvalidTokenError: |
| 128 | + return "无效 Token" |
| 129 | + |
| 130 | +# 示例 |
| 131 | +decoded_data = decode_jwt(token) |
| 132 | +print("解析后的数据:", decoded_data) |
| 133 | +``` |
| 134 | + |
| 135 | +--- |
| 136 | + |
| 137 | +### **5. JWT 进阶** |
| 138 | + |
| 139 | +#### **5.1 使用 RSA 非对称加密** |
| 140 | + |
| 141 | +在上面的示例中,我们使用了 `HS256`(对称加密),这意味着服务器端需要同一个密钥来生成和验证 JWT。 |
| 142 | + |
| 143 | +如果需要**更高的安全性**,可以使用 **RSA(非对称加密)**,客户端用公钥加密,服务器用私钥解密: |
| 144 | + |
| 145 | +```python |
| 146 | +# 生成 RSA 私钥和公钥(仅需一次) |
| 147 | +from cryptography.hazmat.primitives.asymmetric import rsa |
| 148 | +from cryptography.hazmat.primitives import serialization |
| 149 | + |
| 150 | +private_key = rsa.generate_private_key( |
| 151 | + public_exponent=65537, |
| 152 | + key_size=2048 |
| 153 | +) |
| 154 | +public_key = private_key.public_key() |
| 155 | + |
| 156 | +# 转换为可存储格式 |
| 157 | +private_pem = private_key.private_bytes( |
| 158 | + encoding=serialization.Encoding.PEM, |
| 159 | + format=serialization.PrivateFormat.PKCS8, |
| 160 | + encryption_algorithm=serialization.NoEncryption() |
| 161 | +) |
| 162 | + |
| 163 | +public_pem = public_key.public_bytes( |
| 164 | + encoding=serialization.Encoding.PEM, |
| 165 | + format=serialization.PublicFormat.SubjectPublicKeyInfo |
| 166 | +) |
| 167 | + |
| 168 | +# 生成 RSA JWT |
| 169 | +def create_rsa_jwt(user_id: int): |
| 170 | + payload = { |
| 171 | + "user_id": user_id, |
| 172 | + "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1) |
| 173 | + } |
| 174 | + token = jwt.encode(payload, private_pem, algorithm="RS256") |
| 175 | + return token |
| 176 | + |
| 177 | +# 解析 RSA JWT |
| 178 | +def decode_rsa_jwt(token: str): |
| 179 | + try: |
| 180 | + decoded = jwt.decode(token, public_pem, algorithms=["RS256"]) |
| 181 | + return decoded |
| 182 | + except jwt.ExpiredSignatureError: |
| 183 | + return "Token 已过期" |
| 184 | + except jwt.InvalidTokenError: |
| 185 | + return "无效 Token" |
| 186 | + |
| 187 | +# 测试 |
| 188 | +rsa_token = create_rsa_jwt(123) |
| 189 | +print("RSA JWT Token:", rsa_token) |
| 190 | +print("解析 RSA JWT:", decode_rsa_jwt(rsa_token)) |
| 191 | +``` |
| 192 | + |
| 193 | +--- |
| 194 | + |
| 195 | +### **6. JWT 安全性注意事项** |
| 196 | + |
| 197 | +1. **不要存储敏感信息** |
| 198 | + JWT 可以被解码,因此不要在 `payload` 里存储密码或重要机密数据。 |
| 199 | +2. **使用短生命周期** |
| 200 | + 令牌应有一个较短的 `exp` 过期时间,并结合 **刷新 Token 机制** 避免滥用。 |
| 201 | +3. **采用 HTTPS 传输** |
| 202 | + JWT 包含身份信息,必须使用 HTTPS 进行安全传输,防止中间人攻击。 |
| 203 | +4. **尽量使用 **`RS256`** 非对称加密** |
| 204 | + 使用 `RS256` 避免密钥泄露风险,公钥可安全公开,私钥则妥善存储。 |
| 205 | + |
| 206 | +--- |
| 207 | + |
| 208 | +### **7. 总结** |
| 209 | + |
| 210 | ++ JWT 是一种安全、无状态的身份认证机制。 |
| 211 | ++ 由 **Header、Payload、Signature** 三部分组成。 |
| 212 | ++ **HS256** 适合对称加密,**RS256** 适合非对称加密。 |
| 213 | ++ Python 可使用 `jwt` 库进行生成和解析。 |
| 214 | ++ 需要注意 **安全性**,避免敏感数据泄露。 |
| 215 | + |
0 commit comments