TypeScript 中的授权与身份验证:完整指南
在现代 Web 开发中,应用程序安全是一个至关重要的方面。TypeScript 作为 JavaScript 的超集,提供了强大的工具来创建类型安全且安全的授权与身份验证系统。在本文中,我们将探讨关键概念、流行的库,并使用 TypeScript 编写实际示例。
基本概念
在进入代码之前,区分两个术语非常重要:
- 身份验证 (Authentication) — 验证用户的身份(你是谁?)。通常通过登录名/密码、令牌或生物识别来完成。
- 授权 (Authorization) — 确定访问权限(你可以做什么?)。例如,仅允许 "admin" 角色访问管理面板。
TypeScript 的流行库
在 TypeScript/Node.js 生态系统中,有几种经过验证的解决方案:
- Passport.js — 最流行的身份验证策略库(local、JWT、OAuth)。通过
@types/passport类型对 TypeScript 有很好的支持。 - jsonwebtoken — 用于处理 JWT(JSON Web Tokens)。完全类型化。
- bcrypt — 密码哈希。与其他库一起使用。
- express-session — 服务器端会话管理。
示例 1:基于 JWT 的基本身份验证
让我们创建一个简单的令牌访问系统。安装依赖项:
npm install express jsonwebtoken bcrypt @types/express @types/jsonwebtoken @types/bcrypt创建一个带有注册和登录功能的服务器:
import express, { Request, Response } from 'express';import jwt from 'jsonwebtoken';import bcrypt from 'bcrypt';
const app = express();app.use(express.json());
const SECRET_KEY = 'your-secret-key';const users: { username: string; passwordHash: string }[] = [];
// 注册app.post('/register', async (req: Request, res: Response) => { const { username, password } = req.body; const passwordHash = await bcrypt.hash(password, 10); users.push({ username, passwordHash }); res.status(201).json({ message: 'User created' });});
// 登录app.post('/login', async (req: Request, res: Response) => { const { username, password } = req.body; const user = users.find(u => u.username === username); if (!user) return res.status(401).json({ error: 'Invalid credentials' });
const isValid = await bcrypt.compare(password, user.passwordHash); if (!isValid) return res.status(401).json({ error: 'Invalid credentials' });
const token = jwt.sign({ username }, SECRET_KEY, { expiresIn: '1h' }); res.json({ token });});
// 受保护的路由app.get('/protected', (req: Request, res: Response) => { const authHeader = req.headers.authorization; if (!authHeader) return res.status(401).json({ error: 'No token provided' });
const token = authHeader.split(' ')[1]; // Bearer token try { const decoded = jwt.verify(token, SECRET_KEY); res.json({ message: 'Access granted', user: decoded }); } catch { res.status(403).json({ error: 'Invalid token' }); }});
app.listen(3000, () => console.log('Server running on port 3000'));示例 2:基于角色的授权中间件
添加角色模型。创建一个类型化的中间件:
interface JwtPayload { username: string; role: 'user' | 'admin';}
// 用于检查身份验证的中间件function authenticate(req: Request, res: Response, next: Function) { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Unauthorized' });
try { const decoded = jwt.verify(token, SECRET_KEY) as JwtPayload; (req as any).user =