TypeScript 中的 JWT 令牌:完全指南
JSON Web Token (JWT) 是一种基于 JSON 格式创建访问令牌的开放标准 (RFC 7519)。JWT 广泛用于客户端和服务器之间的身份验证和信息交换。在本文中,我们将详细讲解如何使用流行的库和最佳实践在 TypeScript 中处理 JWT 令牌。
什么是 JWT?
JWT 由三部分组成,各部分之间用点分隔:
- Header(头部) — 包含令牌类型和签名算法的信息
- Payload(载荷) — 包含数据(声明),如用户 ID、角色、过期时间
- Signature(签名) — 由头部、载荷和密钥生成
典型的 JWT 如下所示:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c安装 TypeScript 中处理 JWT 的库
为了在 TypeScript 中处理 JWT,我们将使用 jsonwebtoken 库及其类型定义 @types/jsonwebtoken。
npm install jsonwebtokennpm install --save-dev @types/jsonwebtoken在 TypeScript 中创建 JWT 令牌
让我们看一个使用类型化载荷创建 JWT 令牌的示例:
import jwt from 'jsonwebtoken';
// 定义载荷的接口interface TokenPayload { userId: string; email: string; role: 'user' | 'admin';}
// 密钥(在实际项目中请存储在 .env 文件中)const JWT_SECRET = 'your-super-secret-key';
// 创建令牌function generateToken(payload: TokenPayload): string { return jwt.sign(payload, JWT_SECRET, { expiresIn: '1h', // 令牌有效期为 1 小时 issuer: 'pythonlib.ru', subject: payload.userId });}
// 使用示例const userPayload: TokenPayload = { userId: '12345', email: 'user@example.com', role: 'user'};
const token = generateToken(userPayload);console.log('生成的令牌:', token);JWT 的验证和解码
使用以下代码验证令牌的真实性并提取数据:
import jwt, { JwtPayload, VerifyErrors } from 'jsonwebtoken';
interface DecodedToken extends JwtPayload { userId: string; email: string; role: 'user' | 'admin';}
function verifyToken(token: string): DecodedToken | null { try { const decoded = jwt.verify(token, JWT_SECRET) as DecodedToken; return decoded; } catch (error) { if (error instanceof jwt.TokenExpiredError) { console.error('令牌已过期'); } else if (error instanceof jwt.JsonWebTokenError) { console.error('无效的令牌'); } else { console.error('验证错误:', error); } return null; }}
// 验证令牌const decoded = verifyToken(token);if (decoded) { console.log('令牌数据:', decoded); console.log('用户角色:', decoded.role);}Express.js 的中间件(TypeScript)
将 JWT 验证集成到具有完整类型定义的 Express 中间件中:
import { Request, Response, NextFunction } from 'express';import jwt from 'jsonwebtoken';
// 扩展 Request 接口以存储用户数据interface AuthRequest extends Request { user?: { userId: string; email: string; role: 'user' | 'admin'; };}
function authMiddleware(req: AuthRequest, res: Response, next: NextFunction): void { const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) { res.status(401).json({ message: '未提供令牌' }); return; }
const token = authHeader.split(' ')[1];
try { const decoded = jwt.verify(token, JWT_SECRET) as DecodedToken; req.user = { userId: decoded.userId, email: decoded.email, role: decoded.role }; next(); } catch (error) { if (error instanceof jwt.TokenExpiredError) { res.status(401).json({ message: '令牌已过期' }); } else { res.status(401).json({ message: '无效的令牌' }); } }}最佳实践
- 始终将密钥存储在环境变量中,而不是代码中
- 为令牌设置合理的过期时间(例如 15 分钟到 1 小时)
- 使用 HTTPS 传输令牌
- 不要在令牌中存储敏感数据(如密码)
- 实现令牌刷新机制
总结
JWT 令牌是构建现代 Web 应用程序身份验证的强大工具。在 TypeScript 中使用它们可以确保类型安全并减少运行时错误。使用 jsonwebtoken 库,您可以轻松创建、验证和解码令牌,而类型定义则有助于在开发阶段捕获错误。
请记住,安全始终是首要任务:保护您的密钥,使用 HTTPS,并遵循最佳实践来保护您的应用程序和用户数据。