const jwt = require("jsonwebtoken"); const logger = require("../utils/logger"); const { sendError } = require("../utils/response"); const tokenStore = require("./useTokenStore"); const { isTypeInWhitelist, isPathInWhitelist, } = require("../config/auth-whitelist"); /** * 智能鉴权中间件 * 根据请求的 type 参数或路径判断是否需要进行 JWT 验证 * 如果 type 在白名单中或路径在白名单中,则跳过 JWT 验证 */ const smartAuth = (req, res, next) => { try { const requestPath = req.path; // 检查路径是否在白名单中 if (isPathInWhitelist(requestPath)) { console.log(`路径 ${requestPath} 在白名单中,跳过鉴权`); return next(); } // 从请求参数中获取 type(支持 body 和 query) const type = req.body?.type || req.query?.type; // 检查 type 是否在白名单中 if (type && isTypeInWhitelist(type)) { console.log(`请求类型 ${type} 在白名单中,跳过鉴权`); return next(); } // 不在白名单中,执行正常的 JWT 验证 const authHeader = req.headers.authorization; if (!authHeader) { logger.warn(`未授权访问: ${requestPath}, type: ${type}`); return sendError(res, "未提供认证令牌", "No token provided", 401); } // 支持两种格式: "Bearer token" 或 "token" const token = authHeader.startsWith("Bearer ") ? authHeader.substring(7) : authHeader; if (!token) { return sendError(res, "令牌格式错误", "Invalid token format", 401); } const secret = process.env.JWT_SECRET || "your-secret-key"; jwt.verify(token, secret, async (err, decoded) => { if (err) { if (err.name === "TokenExpiredError") { logger.warn(`令牌已过期: ${requestPath}`); return sendError(res, "令牌已过期", "Token expired", 401); } if (err.name === "JsonWebTokenError") { logger.warn(`无效的令牌: ${requestPath}`); return sendError(res, "无效的令牌", "Invalid token", 401); } logger.error("Token验证失败:", err); return sendError(res, "令牌验证失败", "Token verification failed", 401); } if (decoded.platform === 'PC') { const storedToken = await tokenStore.getToken(decoded.userId); if (storedToken !== token) { logger.warn(`令牌不匹配: ${requestPath}`); return sendError(res, "令牌不匹配", "Token does not match", 401); } } // 将解码后的用户信息添加到请求对象 req.user = decoded; console.log(`用户 ${decoded.username || decoded.userId} 鉴权成功`); next(); }); } catch (error) { logger.error("smartAuth中间件错误:", error); return sendError(res, "认证处理失败", error.message, 500); } }; /** * 创建自定义智能鉴权中间件 * 允许在路由级别指定额外的白名单 types * @param {string[]} additionalWhitelist - 额外的白名单 types * @returns {Function} 中间件函数 */ const createSmartAuth = (additionalWhitelist = []) => { return (req, res, next) => { try { const requestPath = req.path; // 检查路径是否在白名单中 if (isPathInWhitelist(requestPath)) { console.log(`路径 ${requestPath} 在白名单中,跳过鉴权`); return next(); } // 从请求参数中获取 type const type = req.body?.type || req.query?.type; // 检查 type 是否在全局白名单或自定义白名单中 if ( type && (isTypeInWhitelist(type) || additionalWhitelist.includes(type)) ) { console.log(`请求类型 ${type} 在白名单中,跳过鉴权`); return next(); } // 执行 JWT 验证(与 smartAuth 相同的逻辑) const authHeader = req.headers.authorization; if (!authHeader) { logger.warn(`未授权访问: ${requestPath}, type: ${type}`); return sendError(res, "未提供认证令牌", "No token provided", 401); } const token = authHeader.startsWith("Bearer ") ? authHeader.substring(7) : authHeader; if (!token) { return sendError(res, "令牌格式错误", "Invalid token format", 401); } const secret = process.env.JWT_SECRET || "your-secret-key"; jwt.verify(token, secret, (err, decoded) => { if (err) { if (err.name === "TokenExpiredError") { logger.warn(`令牌已过期: ${requestPath}`); return sendError(res, "令牌已过期", "Token expired", 401); } if (err.name === "JsonWebTokenError") { logger.warn(`无效的令牌: ${requestPath}`); return sendError(res, "无效的令牌", "Invalid token", 401); } logger.error("Token验证失败:", err); return sendError( res, "令牌验证失败", "Token verification failed", 401 ); } req.user = decoded; console.log(`用户 ${decoded.username || decoded.userId} 鉴权成功`); next(); }); } catch (error) { logger.error("createSmartAuth中间件错误:", error); return sendError(res, "认证处理失败", error.message, 500); } }; }; module.exports = { smartAuth, createSmartAuth, };