乐闻世界logo
搜索文章和话题

JWT 在实际应用中会遇到哪些常见问题,如何解决

2026年2月21日 17:53

JWT 在实际应用中会面临各种常见问题,以下是这些问题及其解决方案:

1. Token 泄露问题

问题

JWT 存储在客户端,可能通过 XSS 攻击被窃取。

解决方案

javascript
// 使用 HttpOnly Cookie 存储 JWT app.use((req, res, next) => { res.cookie('token', token, { httpOnly: true, // 防止 JavaScript 访问 secure: true, // 仅 HTTPS 传输 sameSite: 'strict', // 防止 CSRF maxAge: 900000 // 15分钟 }); next(); }); // 或者使用双重提交 Cookie 模式 app.post('/api/data', (req, res) => { const token = req.cookies.token; const csrfToken = req.headers['x-csrf-token']; // 验证 CSRF token if (!validateCsrfToken(csrfToken)) { return res.status(403).json({ error: 'Invalid CSRF token' }); } // 验证 JWT const decoded = jwt.verify(token, SECRET_KEY); // ... });

2. Token 无法主动撤销

问题

JWT 一旦签发,在过期前无法主动撤销。

解决方案

javascript
// 使用 Redis 实现黑名单 const redis = require('redis'); const client = redis.createClient(); // 登出时将 token 加入黑名单 async function revokeToken(token) { const decoded = jwt.decode(token); const ttl = decoded.exp - Math.floor(Date.now() / 1000); if (ttl > 0) { await client.setex(`blacklist:${token}`, ttl, '1'); } } // 验证时检查黑名单 async function verifyToken(token) { const isBlacklisted = await client.exists(`blacklist:${token}`); if (isBlacklisted) { throw new Error('Token has been revoked'); } return jwt.verify(token, SECRET_KEY); }

3. Token 过期时间过长

问题

Token 过期时间过长会增加安全风险。

解决方案

javascript
// 使用短期 Access Token + 长期 Refresh Token const accessToken = jwt.sign( { userId: user.id }, SECRET_KEY, { expiresIn: '15m' } // 短期 ); const refreshToken = crypto.randomBytes(40).toString('hex'); await storeRefreshToken(refreshToken, user.id, '7d'); // 长期

4. Payload 信息泄露

问题

JWT 的 Payload 只是 Base64 编码,任何人都可以解码查看。

解决方案

javascript
// 不存储敏感信息 const token = jwt.sign({ userId: user.id, // ✅ 只存储 ID role: user.role // ✅ 只存储角色 // ❌ 不要存储密码、手机号等敏感信息 }, SECRET_KEY); // 如需传输敏感数据,使用 JWE 加密 const { JWE } = require('jose'); async function encryptToken(payload) { const jwe = await new JWE.Encrypt(payload) .setProtectedHeader({ alg: 'RSA-OAEP', enc: 'A256GCM' }) .encrypt(publicKey); return jwe; }

5. 跨域问题

问题

JWT 在跨域请求中可能遇到 CORS 问题。

解决方案

javascript
// 服务器端配置 CORS const cors = require('cors'); app.use(cors({ origin: ['https://example.com', 'https://app.example.com'], credentials: true, // 允许携带 Cookie methods: ['GET', 'POST', 'PUT', 'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'] })); // 前端发送请求时携带凭证 fetch('https://api.example.com/data', { method: 'GET', credentials: 'include', // 携带 Cookie headers: { 'Authorization': `Bearer ${token}` } });

6. Token 大小问题

问题

JWT 包含较多信息时,token 体积过大,影响传输性能。

解决方案

javascript
// 1. 使用更短的算法(ES256 vs RS256) const token = jwt.sign(payload, privateKey, { algorithm: 'ES256' // 比 RS256 小约 50% }); // 2. 只存储必要信息 const token = jwt.sign({ uid: user.id, // 使用短字段名 r: user.role // 使用缩写 }, SECRET_KEY); // 3. 使用压缩 const { deflate } = require('pako'); const compressed = deflate(JSON.stringify(payload));

7. 多设备登录问题

问题

用户在多个设备登录,需要管理不同设备的 token。

解决方案

javascript
// 为每个设备生成独立的 refresh token app.post('/auth/login', async (req, res) => { const { username, password, deviceInfo } = req.body; const user = await validateUser(username, password); const accessToken = generateAccessToken(user.id); const refreshToken = generateRefreshToken(); // 存储设备信息 await storeDeviceToken(user.id, { refreshToken, deviceInfo, lastUsed: Date.now() }); res.json({ accessToken, refreshToken }); }); // 获取所有登录设备 app.get('/auth/devices', authMiddleware, async (req, res) => { const devices = await getUserDevices(req.user.userId); res.json(devices); }); // 登出指定设备 app.post('/auth/logout-device', authMiddleware, async (req, res) => { const { refreshToken } = req.body; await deleteDeviceToken(req.user.userId, refreshToken); res.json({ success: true }); }); // 登出所有设备 app.post('/auth/logout-all', authMiddleware, async (req, res) => { await deleteAllDeviceTokens(req.user.userId); res.json({ success: true }); });

8. 性能问题

问题

每次请求都需要验证 JWT 签名,影响性能。

解决方案

javascript
// 1. 使用缓存 const NodeCache = require('node-cache'); const tokenCache = new NodeCache({ stdTTL: 300 }); // 5分钟缓存 function verifyTokenCached(token) { const cacheKey = `token:${token}`; let decoded = tokenCache.get(cacheKey); if (!decoded) { decoded = jwt.verify(token, SECRET_KEY); tokenCache.set(cacheKey, decoded); } return decoded; } // 2. 使用更快的算法(ES256) const token = jwt.sign(payload, privateKey, { algorithm: 'ES256' // 比 RS256 快 }); // 3. 批量验证 function verifyTokens(tokens) { return tokens.map(token => { try { return { token, valid: true, decoded: jwt.verify(token, SECRET_KEY) }; } catch (error) { return { token, valid: false, error: error.message }; } }); }

9. 密钥管理问题

问题

密钥管理不当会导致严重安全问题。

解决方案

javascript
// 1. 使用环境变量 const SECRET_KEY = process.env.JWT_SECRET; // 2. 使用密钥管理服务 const AWS = require('aws-sdk'); const kms = new AWS.KMS(); async function getSecretKey() { const result = await kms.decrypt({ CiphertextBlob: Buffer.from(process.env.ENCRYPTED_SECRET, 'base64') }).promise(); return result.Plaintext.toString(); } // 3. 密钥轮换 const keyVersions = { v1: 'old-secret-key', v2: 'current-secret-key', v3: 'new-secret-key' }; function verifyTokenWithKeyRotation(token) { // 尝试使用所有密钥验证 for (const [version, key] of Object.entries(keyVersions)) { try { const decoded = jwt.verify(token, key); decoded.keyVersion = version; return decoded; } catch (error) { continue; } } throw new Error('Invalid token'); }

10. 审计和监控

问题

需要监控 JWT 的使用情况,发现异常行为。

解决方案

javascript
// 记录 token 使用日志 async function logTokenUsage(token, action) { const decoded = jwt.decode(token); await db.insert('token_logs', { userId: decoded.userId, token: token.substring(0, 20) + '...', // 只记录部分 action, ip: req.ip, userAgent: req.headers['user-agent'], timestamp: Date.now() }); } // 检测异常使用 async function detectAnomalousUsage(userId) { const logs = await getTokenLogs(userId, 24 * 60 * 60 * 1000); // 24小时 const uniqueIPs = new Set(logs.map(log => log.ip)); const uniqueLocations = new Set(logs.map(log => log.location)); if (uniqueIPs.size > 10 || uniqueLocations.size > 5) { // 可能存在异常,发送警报 await sendAlert(userId, 'Suspicious token usage detected'); } }

最佳实践总结

  1. 使用 HttpOnly Cookie 存储 JWT
  2. 实现 Token 黑名单 支持主动撤销
  3. 使用短期 Access Token + 长期 Refresh Token
  4. 不在 Payload 中存储敏感信息
  5. 正确配置 CORS 支持跨域
  6. 优化 Token 大小 提高性能
  7. 实现多设备管理
  8. 使用缓存提升性能
  9. 安全地管理密钥
  10. 实施审计和监控

通过解决这些常见问题,可以构建更安全、更可靠的 JWT 认证系统。

标签:JWT