import { DBModel } from '../models/index.js'; import ResponseUtil from '../utils/api_response.js'; /** * 从请求中提取 token(优先 Authorization header) */ function extractToken(ctx) { // 优先从 Authorization: Bearer xxx 获取 const authHeader = ctx.header?.authorization; if (authHeader && authHeader.startsWith('Bearer ')) { return authHeader.slice(7); } // 兼容旧方式:body/query/header 中的 token 字段 return ctx.request.body?.token || ctx.request.query?.token || ctx.header?.token; } /** * 认证中间件 - 验证 token 并挂载用户信息到 ctx * 可选参数: * - required: 是否必须登录(默认 true) * - roles: 允许的角色列表(可选) */ function auth(options = {}) { const { required = true, roles } = options; return async (ctx, next) => { const token = extractToken(ctx); if (!token) { if (!required) { ctx.state.user = null; return await next(); } return ResponseUtil.unauthorized(ctx, '缺少认证 token'); } const user = await DBModel.User.findOne({ 'security.token': token }); if (!user) { return ResponseUtil.unauthorized(ctx, '用户未登录或 token 无效'); } if (user.security.tokenExpiry && new Date() > user.security.tokenExpiry) { return ResponseUtil.unauthorized(ctx, '登录已过期,请重新登录'); } if (user.status.account === 'lock') { return ResponseUtil.forbidden(ctx, '账户已被锁定'); } // 角色检查 if (roles && roles.length > 0) { const hasRole = roles.some(role => { // 检查 app 字段中的角色 return Object.values(user.app || {}).some(appData => appData && Array.isArray(appData.role) && appData.role.includes(role) ); }); if (!hasRole) { return ResponseUtil.forbidden(ctx, '权限不足'); } } ctx.state.user = user; await next(); }; } /** * 返回用户安全对象(去除密码等敏感字段) */ function sanitizeUser(user) { const obj = user.toObject ? user.toObject() : { ...user }; delete obj.security?.passwd; delete obj.security?.passwdSalt; delete obj.security?.passwordResetToken; delete obj.security?.passwordResetExpiry; return obj; } export { auth, extractToken, sanitizeUser };