TypeScript中的授权与身份验证:从理论到实践
在现代Web开发中,应用程序安全是基石。TypeScript作为JavaScript的严格类型化超集,为构建可靠的身份验证(验证用户身份)和授权(验证访问权限)系统提供了强大的工具。在本文中,我们将探讨关键概念、流行库,并用TypeScript编写一个可运行的示例。
基本概念:身份验证 vs 授权
这两个术语经常被混淆。让我们明确区分:
- 身份验证(Authentication) — 验证您是谁的过程。例如,通过用户名和密码登录,或通过第三方服务(Google、GitHub)登录。
- 授权(Authorization) — 验证您可以做什么的过程。例如,访问管理面板或删除帖子的权限。
在TypeScript中,这些过程通过中间件(中间处理程序)实现,在执行请求之前检查令牌或会话。
TypeScript的流行库
在TypeScript项目中实现授权与身份验证时,最常用的库包括:
jsonwebtoken— 用于处理JWT(JSON Web令牌)。bcrypt— 用于密码哈希。passport(配合类型@types/passport)— 用于Express的灵活中间件。express-session— 用于服务器端会话管理。crypto— Node.js内置模块,用于哈希处理。
实践示例:TypeScript中的JWT身份验证
让我们创建一个简单的REST API,通过JWT进行身份验证。示例将基于Express + TypeScript。
步骤1. 安装依赖
npm install express jsonwebtoken bcrypt dotenvnpm install -D typescript @types/express @types/jsonwebtoken @types/bcrypt ts-node nodemon步骤2. TypeScript配置(tsconfig.json)
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true }}步骤3. 创建身份验证中间件
// src/middleware/auth.tsimport { Request, Response, NextFunction } from 'express';import jwt from 'jsonwebtoken';
interface UserPayload { id: string; email: string;}
// 扩展Request接口以存储用户数据declare global { namespace Express { interface Request { user?: UserPayload; } }}
export const authenticate = ( req: Request, 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, process.env.JWT_SECRET || 'default_secret' ) as UserPayload; req.user = decoded; next(); } catch (error) { res.status(401).json({ message: '无效令牌' }); }};步骤4. 基于角色的授权中间件
// src/middleware/authorize.tsimport { Request, Response, NextFunction } from 'express';
export const authorize = (...allowedRoles: string[]) => { return (req: Request, res: Response, next: NextFunction): void => { // 假设角色在身份验证后存储在req.user中 const userRole = (req as any).user?.role || 'user';
if (!allowedRoles.includes(userRole)) { res.status(403).json({ message: '访问被拒绝' });