fix(iter-v2): T01 QA fixes - race condition, hook regex, deleted user check
- BUG-1: Pre-commit hook allows .env.example (grep -v filter) - BUG-2: /auth/refresh uses transaction + FOR UPDATE to prevent race condition - WARN-1: Auth middleware checks deleted_at with 5-min TTL cache - WARN-2: PUT /admin/users/:id/status filters deleted_at IS NULL - WARN-3: Install node-cron@^3.0.3
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Request, Response, NextFunction } from 'express'
|
||||
import { createHmac, timingSafeEqual } from 'crypto'
|
||||
import { TOKEN_SECRET } from '../config/token'
|
||||
import pool from '../db/connection'
|
||||
|
||||
export interface AuthRequest extends Request {
|
||||
userId?: number
|
||||
@@ -11,7 +12,24 @@ const TOKEN_EXPIRY = 2 * 60 * 60 * 1000 // 2 hours
|
||||
// 不需要认证的路径
|
||||
const PUBLIC_PATHS = ['/api/auth/login', '/api/auth/demo-login', '/api/auth/refresh', '/api/health']
|
||||
|
||||
export function authMiddleware(req: AuthRequest, res: Response, next: NextFunction) {
|
||||
/** 已删除用户 ID 缓存(5 分钟 TTL) */
|
||||
const deletedUserCache = new Map<number, number>() // userId → cachedAt
|
||||
|
||||
async function isUserDeleted(userId: number): Promise<boolean> {
|
||||
const cached = deletedUserCache.get(userId)
|
||||
if (cached && Date.now() - cached < 5 * 60 * 1000) {
|
||||
return true // 仍在缓存中,视为已删除
|
||||
}
|
||||
const [rows] = await pool.query('SELECT deleted_at FROM users WHERE id = ?', [userId])
|
||||
if (!(rows as any[]).length || (rows as any[])[0].deleted_at !== null) {
|
||||
deletedUserCache.set(userId, Date.now())
|
||||
return true
|
||||
}
|
||||
deletedUserCache.delete(userId)
|
||||
return false
|
||||
}
|
||||
|
||||
export async function authMiddleware(req: AuthRequest, res: Response, next: NextFunction) {
|
||||
// 公开路径跳过认证
|
||||
if (PUBLIC_PATHS.some(p => req.path === p)) {
|
||||
return next()
|
||||
@@ -57,6 +75,11 @@ export function authMiddleware(req: AuthRequest, res: Response, next: NextFuncti
|
||||
return res.status(401).json({ code: 40100, message: 'token无效' })
|
||||
}
|
||||
|
||||
// 检查用户是否已被软删除
|
||||
if (await isUserDeleted(userId)) {
|
||||
return res.status(401).json({ code: 40100, message: '账号已禁用' })
|
||||
}
|
||||
|
||||
req.userId = userId
|
||||
} catch {
|
||||
return res.status(401).json({ code: 40100, message: 'token无效' })
|
||||
|
||||
Reference in New Issue
Block a user