const jwt = require('jsonwebtoken'); const crypto = require('crypto'); const { UserDB } = require('./database'); // JWT密钥(必须在环境变量中设置) const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production'; // Refresh Token密钥(使用不同的密钥) const REFRESH_SECRET = process.env.REFRESH_SECRET || JWT_SECRET + '-refresh'; // Token有效期配置 const ACCESS_TOKEN_EXPIRES = '2h'; // Access token 2小时 const REFRESH_TOKEN_EXPIRES = '7d'; // Refresh token 7天 // 安全检查:验证JWT密钥配置 const DEFAULT_SECRETS = [ 'your-secret-key-change-in-production', 'your-secret-key-change-in-production-PLEASE-CHANGE-THIS' ]; if (DEFAULT_SECRETS.includes(JWT_SECRET)) { const errorMsg = ` ╔═══════════════════════════════════════════════════════════════╗ ║ ⚠️ 安全警告 ⚠️ ║ ╠═══════════════════════════════════════════════════════════════╣ ║ JWT_SECRET 使用默认值,存在严重安全风险! ║ ║ ║ ║ 请立即设置环境变量 JWT_SECRET ║ ║ 生成随机密钥: ║ ║ node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" ║ ║ ║ 在 backend/.env 文件中设置: ║ ║ JWT_SECRET=你生成的随机密钥 ║ ╚═══════════════════════════════════════════════════════════════╝ `; if (process.env.NODE_ENV === 'production') { console.error(errorMsg); throw new Error('生产环境必须设置 JWT_SECRET!'); } else { console.warn(errorMsg); } } console.log('[安全] JWT密钥已配置'); // 生成Access Token(短期) function generateToken(user) { return jwt.sign( { id: user.id, username: user.username, is_admin: user.is_admin, type: 'access' }, JWT_SECRET, { expiresIn: ACCESS_TOKEN_EXPIRES } ); } // 生成Refresh Token(长期) function generateRefreshToken(user) { return jwt.sign( { id: user.id, type: 'refresh', // 添加随机标识,使每次生成的refresh token不同 jti: crypto.randomBytes(16).toString('hex') }, REFRESH_SECRET, { expiresIn: REFRESH_TOKEN_EXPIRES } ); } // 验证Refresh Token并返回新的Access Token function refreshAccessToken(refreshToken) { try { const decoded = jwt.verify(refreshToken, REFRESH_SECRET); if (decoded.type !== 'refresh') { return { success: false, message: '无效的刷新令牌类型' }; } const user = UserDB.findById(decoded.id); if (!user) { return { success: false, message: '用户不存在' }; } if (user.is_banned) { return { success: false, message: '账号已被封禁' }; } if (!user.is_active) { return { success: false, message: '账号未激活' }; } // 生成新的access token const newAccessToken = generateToken(user); return { success: true, token: newAccessToken, user: { id: user.id, username: user.username, is_admin: user.is_admin } }; } catch (error) { if (error.name === 'TokenExpiredError') { return { success: false, message: '刷新令牌已过期,请重新登录' }; } return { success: false, message: '无效的刷新令牌' }; } } // 验证Token中间件 function authMiddleware(req, res, next) { // 从请求头或HttpOnly Cookie获取token(不再接受URL参数以避免泄露) const token = req.headers.authorization?.replace('Bearer ', '') || req.cookies?.token; if (!token) { return res.status(401).json({ success: false, message: '未提供认证令牌' }); } try { const decoded = jwt.verify(token, JWT_SECRET); const user = UserDB.findById(decoded.id); if (!user) { return res.status(401).json({ success: false, message: '用户不存在' }); } if (user.is_banned) { return res.status(403).json({ success: false, message: '账号已被封禁' }); } if (!user.is_active) { return res.status(403).json({ success: false, message: '账号未激活' }); } // 将用户信息附加到请求对象(包含所有存储相关字段) req.user = { id: user.id, username: user.username, email: user.email, is_admin: user.is_admin, has_ftp_config: user.has_ftp_config, ftp_host: user.ftp_host, ftp_port: user.ftp_port, ftp_user: user.ftp_user, ftp_password: user.ftp_password, http_download_base_url: user.http_download_base_url, // 存储相关字段(v2.0新增) storage_permission: user.storage_permission || 'sftp_only', current_storage_type: user.current_storage_type || 'sftp', local_storage_quota: user.local_storage_quota || 1073741824, local_storage_used: user.local_storage_used || 0, // 主题偏好 theme_preference: user.theme_preference || null }; next(); } catch (error) { if (error.name === 'TokenExpiredError') { return res.status(401).json({ success: false, message: '令牌已过期' }); } return res.status(401).json({ success: false, message: '无效的令牌' }); } } // 管理员权限中间件 function adminMiddleware(req, res, next) { if (!req.user || !req.user.is_admin) { return res.status(403).json({ success: false, message: '需要管理员权限' }); } next(); } // 检查JWT密钥是否安全 function isJwtSecretSecure() { return !DEFAULT_SECRETS.includes(JWT_SECRET) && JWT_SECRET.length >= 32; } module.exports = { JWT_SECRET, generateToken, generateRefreshToken, refreshAccessToken, authMiddleware, adminMiddleware, isJwtSecretSecure, ACCESS_TOKEN_EXPIRES, REFRESH_TOKEN_EXPIRES };