M-Uzair-dev/RedAuth
GitHub: M-Uzair-dev/RedAuth
一个生产就绪的 Express/TypeScript 认证微服务模板,提供多设备会话管理、令牌轮换和安全防护等企业级特性。
Stars: 1 | Forks: 0
# RedAuth
一个生产就绪的 Express + TypeScript 认证后端。开箱即用的安全、设备感知会话 —— 拿来即用,以此为基础进行构建。
**作者:** Uzair Manan
**许可证:** ISC
**代码库:** [M-Uzair-dev/Authetication-Template](https://github.com/M-Uzair-dev/Authetication-Template)
**问题反馈:** [GitHub Issues](https://github.com/M-Uzair-dev/Authetication-Template/issues)
## 功能特性
- 双令牌会话管理(通过 httpOnly cookies 实现访问 + 刷新 JWT)
- 设备作用域会话 —— 每个用户每台设备一个刷新令牌,支持多个并发会话
- 刷新令牌轮换,并自动检测盗用(检测到重放攻击时清除所有会话)
- 基于 Redis 的滑动窗口速率限制、用户缓存和即时令牌撤销
- BullMQ 工作队列,用于带有重试和退避机制的异步邮件投递
- 定时的令牌清理 cron(每 10 分钟)
- 每个端点均进行 Zod v4 输入验证
- 对所有敏感端点(忘记密码、重发邮件、登录)进行时序攻击缓解
- 用于验证、登录警报和密码重置的 HTML 邮件模板
## 技术栈
| 层级 | 技术 |
|---|---|
| 运行时 | Node.js v20+ (ESM) |
| 框架 | Express 5 |
| 语言 | TypeScript (NodeNext 模块解析) |
| 数据库 | PostgreSQL via Prisma 7 + `pg` 连接池适配器 |
| 缓存 / 队列代理 | Redis via ioredis |
| 后台任务 | BullMQ |
| 校验 | Zod 4 |
| 认证 | jsonwebtoken + bcrypt (cost 12) |
| 邮件 | Nodemailer |
| 安全头 | Helmet |
## 文件结构
```
AuthTemplate/
├── src/
│ ├── index.ts # App entry — middleware stack, routes, server start
│ ├── controllers/
│ │ ├── auth.controller.ts # Login, signup, password reset, email verification, logout
│ │ └── user.controller.ts # Get/update/delete user, sessions, revoke session
│ ├── services/
│ │ ├── auth.service.ts # Core auth business logic
│ │ ├── token.service.ts # JWT signing, verification, rotation, revocation
│ │ ├── email.service.ts # Email template rendering + BullMQ job dispatch
│ │ └── user.service.ts # User CRUD, session queries
│ ├── routes/
│ │ ├── auth.route.ts # /auth/* route definitions + rate limiter attachment
│ │ └── user.route.ts # /user/* route definitions
│ ├── middleware/
│ │ └── verifyUser.ts # JWT auth middleware, sets req.userId, records last-active
│ ├── schemas/
│ │ ├── auth.schema.ts # Zod schemas for all auth endpoint inputs
│ │ └── user.schema.ts # Zod schemas for user update and session revoke
│ ├── errors/
│ │ └── errors.ts # appError class + errorType enum
│ ├── utils/
│ │ ├── rateLimiter.ts # Redis sliding window rate limiter factory
│ │ ├── cacheUser.ts # Redis user cache read/write/delete (Zod-validated)
│ │ ├── handleError.ts # Centralized error handler (appError, ZodError, unknown)
│ │ └── getRequestInfo.ts # Parses User-Agent + IP for login metadata
│ ├── lib/
│ │ ├── prisma.ts # Prisma client singleton with pg pool adapter
│ │ └── redis.ts # ioredis client singleton
│ ├── queues/
│ │ ├── email.queue.ts # BullMQ email queue definition
│ │ └── tokenCleanup.queue.ts # BullMQ cleanup queue with repeating job
│ ├── workers/
│ │ ├── email.worker.ts # Processes email jobs, handles retry/failure cleanup
│ │ └── tokenCleanup.worker.ts # Deletes expired tokens from DB every 10 minutes
│ ├── emails/
│ │ ├── emailVerification.html # Verification email template
│ │ ├── loginAlert.html # Login alert email template
│ │ └── passwordReset.html # Password reset email template
│ └── types/
│ └── express.d.ts # Express Request augmentation (req.userId)
├── prisma/
│ ├── schema.prisma # User + Token models
│ └── migrations/ # Migration history
├── postman-collection.json # Importable Postman collection (all 14 endpoints)
├── API_ROUTES.md # Full API reference — request/response shapes
├── env_example.txt # All required environment variables with defaults
├── package.json
└── tsconfig.json
```
## 前置条件
- **Node.js** v20+
- **PostgreSQL** 数据库(本地或托管)
- **Redis** 服务器(本地 Docker 或托管)
- **SMTP 凭证**(例如 Gmail 应用密码)
## 设置
### 1. 克隆 & 安装
```
git clone https://github.com/M-Uzair-dev/Authetication-Template.git
cd Authetication-Template
npm install
```
### 2. 环境变量
```
cp env_example.txt .env
```
填写所有值:
| 变量 | 描述 | 默认值 |
|---|---|---|
| `DATABASE_URL` | PostgreSQL 连接字符串 | — |
| `ACCESS_TOKEN_SECRET` | 用于访问令牌的 JWT 签名密钥 | — |
| `ACCESS_TOKEN_EXPIRY` | 访问令牌有效期(**毫秒**) | `900000` (15 分钟) |
| `REFRESH_TOKEN_SECRET` | 用于刷新令牌的 JWT 签名密钥 | — |
| `REFRESH_TOKEN_EXPIRY` | 刷新令牌有效期(**毫秒**) | `604800000` (7 天) |
| `RESET_TOKEN_SECRET` | 用于密码重置令牌的 JWT 签名密钥 | — |
| `RESET_TOKEN_EXPIRY` | 重置令牌有效期(**毫秒**) | `1800000` (30 分钟) |
| `VERIFICATION_TOKEN_SECRET` | 用于邮箱验证令牌的 JWT 签名密钥 | — |
| `VERIFICATION_TOKEN_EXPIRY` | 验证令牌有效期(**毫秒**) | `172800000` (2 天) |
| `MAIL_HOST` | SMTP 主机 | `smtp.gmail.com` |
| `MAIL_PORT` | SMTP 端口 | `587` |
| `MAIL_USER` | SMTP 用户名 / 发件人地址 | — |
| `MAIL_PASS` | SMTP 密码或应用密码 | — |
| `REDIS_HOST` | Redis 主机 | `127.0.0.1` |
| `REDIS_PORT` | Redis 端口 | `6379` |
| `FRONTEND_URL` | 前端基础 URL(用于邮件链接) | — |
### 3. Redis
```
# 首次运行 — 下载 image 并启动 container
docker run -d --name redis-server -p 6379:6379 redis
# 后续启动
docker start redis-server
```
### 4. 数据库
```
# 应用 migrations
npx prisma migrate deploy
# 开发期间重置
npx prisma migrate reset
# 打开 Prisma Studio (GUI)
npx prisma studio
```
### 5. 运行
```
# 开发 (TypeScript watch + nodemon)
npm run dev
# 生产环境
npm run build
npm start
```
服务器在 `PORT`(默认 `5000`)上启动。
## API
所有 14 个端点的完整请求/响应文档位于 **[API_ROUTES.md](API_ROUTES.md)**。
### 路由概览
| 方法 | 路径 | 认证 | 描述 |
|---|---|---|---|
| `POST` | `/auth/signup` | — | 注册新账户 |
| `POST` | `/auth/login` | — | 使用邮箱 + 密码登录 |
| `POST` | `/auth/forgotPassword` | — | 发送密码重置邮件 |
| `POST` | `/auth/resetPassword` | — | 通过令牌重置密码 |
| `POST` | `/auth/verifyEmail` | — | 通过令牌验证邮箱 |
| `POST` | `/auth/resendVerificationEmail` | — | 重发验证邮件 |
| `POST` | `/auth/logout` | 是 | 登出当前设备 |
| `POST` | `/auth/logout-all` | 是 | 登出所有设备 |
| `POST` | `/auth/get-access-token` | — | 使用刷新 cookie 轮换令牌 |
| `GET` | `/user/me` | 是 | 获取当前用户 |
| `PATCH` | `/user/me` | 是 | 更新当前用户 |
| `DELETE` | `/user/me` | 是 | 删除账户 |
| `GET` | `/user/sessions` | 是 | 列出所有活跃会话 |
| `POST` | `/user/revoke-session` | 是 | 撤销特定会话 |
### Postman
将仓库根目录下的 `postman-collection.json` 导入 Postman。将 `{{baseUrl}}` 变量设置为 `http://localhost:5000`。
## 架构
### 令牌流程
```
Login / Signup
└─ generateTokens()
├─ Signs access JWT { id, email, tokenId } (15 min)
├─ Signs refresh JWT { id, email, tokenId } (7 days)
└─ Upserts refresh token hash into Token table (keyed on userId + device)
→ Both set as httpOnly cookies
Authenticated request
└─ verifyUser middleware
├─ Verifies access token signature
├─ Checks Redis for revoked-{tokenId} key
└─ Sets req.userId, records last-active-{tokenId} in Redis (TTL: 7 days)
Access token expired → client calls POST /auth/get-access-token
└─ Verifies refresh token
├─ tokenId not in DB → wipe ALL sessions (theft detected)
└─ Rotate: delete old record, mint new access + refresh pair
Logout
└─ Deletes refresh token from DB
└─ Sets revoked-{tokenId} in Redis (TTL: 30 min) for instant revocation
```
### 速率限制
| 限制器 | 应用于 | 限制 |
|---|---|---|
| `generalLimiter` | 所有路由 | 每 IP 60 秒内 100 次请求 |
| `strictAuthLimiter` | login, signup, resetPassword, verifyEmail, logout, logout-all, get-access-token | 每 IP 5 分钟内 10 次请求 |
| `stricterEmailLimiter` | forgotPassword, resendVerificationEmail | 每 IP 5 分钟内 3 次请求 |
通过 Redis 有序集合滑动窗口实现 —— 可在多个服务器实例间正确工作。
### 邮件队列
- 通过 BullMQ 异步分发任务(并发数:5)
- 3 次重试尝试,从 5 秒开始的指数退避
- 最终失败时:从数据库中删除孤立的令牌记录
- 触发条件:signup (验证), login (警报), forgot password (重置链接)
### 数据库模式
**User** — `id`, `name`, `email` (唯一), `password` (bcrypt), `emailVerified`, `createdAt`, `updatedAt`
**Token** — `id`, `userId` (外键级联), `type` (EMAIL_VERIFICATION | PASSWORD_RESET | REFRESH_TOKEN), `tokenHash` (JWT 的 SHA-256), `device`, `deviceName`, `lastActive`, `expiresAt`, `createdAt`
索引:`userId`, `tokenHash`, 唯一 `(userId, device, type)`
## CORS
为 `http://localhost:3000` 配置,并启用 `credentials: true`。在部署之前,更新 `src/index.ts` 以从 `process.env.FRONTEND_URL` 读取 origin。
## 许可证
ISC
标签:BullMQ, Express, GNU通用公共许可证, JWT, MITM代理, Modbus, Node.js, Nodemailer, PostgreSQL, Prisma, Redis, Syscall, TypeScript, Web开发, Zod, 企业级, 会话管理, 双Token, 后台, 多设备登录, 安全, 安全插件, 异步任务, 搜索引擎查询, 权限校验, 模板, 测试用例, 自动化攻击, 超时处理, 防盗刷