OAuth 2.0 和 JWT 授权在 TypeScript 上:面向初学者
现代 Web 应用程序很少能离开身份验证和授权机制。两个最流行的标准是 OAuth 2.0(访问委托协议)和 JWT(JSON Web Token,一种紧凑的数据传输方式)。在本文中,我们将探讨如何在 TypeScript 上实现 OAuth 2.0 和 JWT 授权,创建一个简单但可用的服务器。本材料面向熟悉 TypeScript 和 Node.js 基础的初学者开发者。
什么是 OAuth 2.0 和 JWT?
在编写代码之前,理解理论很重要。
OAuth 2.0
这是一个协议,允许用户授予第三方应用程序对其资源的有限访问权限(例如,GitHub 或 Google 上的个人资料),而无需传递登录名和密码。OAuth 2.0 中有几个角色:
- Resource Owner — 资源所有者(用户)。
- Client — 希望获得访问权限的应用程序。
- Authorization Server — 在成功身份验证后颁发令牌的服务器。
- Resource Server — 存储受保护数据的服务器。
最常见的场景是“授权码流程”,用户被重定向到提供商的页面,登录,然后服务器将获得的代码交换为令牌。
JWT(JSON Web Token)
JWT 是一个格式为 header.payload.signature 的字符串,包含数据(声明)并使用密钥签名。它在 OAuth 2.0 中用作 Access Token(短期)或 Refresh Token(长期)。JWT 的优势在于它是自包含的:服务器无需访问数据库即可验证它。
项目设置和依赖安装
创建一个新的 TypeScript 项目。确保您已安装 Node.js 和 npm。
mkdir oauth-jwt-typescriptcd oauth-jwt-typescriptnpm init -ynpm install express jsonwebtoken dotenv cors cookie-parsernpm install -D typescript @types/node @types/express @types/jsonwebtoken @types/cors @types/cookie-parser ts-node nodemonnpx tsc --init在 tsconfig.json 文件中,取消注释 "outDir": "./dist" 行,并设置 "rootDir": "./src"。创建文件夹结构:
src/ ├── index.ts ├── auth.ts ├── middleware.ts └── types.ts.env在 .env 文件中指定:
ACCESS_TOKEN_SECRET=your-secret-key-123REFRESH_TOKEN_SECRET=your-refresh-secret-456PORT=3000使用 OAuth 2.0 和 JWT 实现服务器
1. 服务器基本结构(index.ts)
编写一个简单的 Express 服务器,包含登录、获取令牌和受保护端点的路由。
import express from 'express';import cors from 'cors';import cookieParser from 'cookie-parser';import dotenv from 'dotenv';import { login, refresh, logout } from './auth';import { authenticateToken } from './middleware';
dotenv.config();
const app = express();app.use(express.json());app.use(cors());app.use(cookieParser());
// 公共路由app.get('/', (req, res) => { res.send('OAuth 2.0 + JWT Server is running');});
// 身份验证(模拟 OAuth 2.0)app.post('/login', login);app.post('/token', refresh); // 刷新 Access Tokenapp.delete('/logout', logout);
// 受保护路由app.get('/protected', authenticateToken, (req, res) => { res.json({ message: '访问已授权', user: (req as any).user });});
app.listen(process.env.PORT, () => { console.log(`Server running on port ${process.env.PORT}`);});2. 数据类型(types.ts)
export interface TokenPayload { userId: number; username: string;}
export int