chenpei d0dc94e36d feat: 将弹幕功能替换为AI聊天助手
新功能:
- 创建AI聊天助手组件(AIChatWidget)
- 支持文字+图片多模态对话
- 集成Gemini AI API
- 支持图片编辑和内容生成
- 实时对话历史管理
- 优雅的UI设计,支持黑夜模式

技术实现:
- 后端API代理Gemini API(/api/ai-chat)
- 支持最多5张图片上传
- 流式响应处理
- 对话历史管理
- Base64图片处理

配置:
- 在.env中添加Gemini API配置
- GEMINI_API_KEY
- GEMINI_API_BASE_URL
- GEMINI_MODEL

替换原弹幕功能,提供更强大的AI助手体验!
2025-10-27 17:45:37 +08:00

270 lines
8.2 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const jwt = require('jsonwebtoken');
const User = require('../models/User');
const mongoose = require('mongoose');
// 获取 JWT 密钥
const getJwtSecret = () => process.env.JWT_SECRET || 'your-secret-key';
/**
* 检查数据库连接状态
* @returns {boolean} 数据库是否已连接
*/
const isDatabaseConnected = () => {
return mongoose.connection.readyState === 1;
};
/**
* 验证用户是否已登录的中间件
* 如果验证成功,将用户信息添加到req.user
*/
const requireAuth = async (req, res, next) => {
try {
// 首先检查会话中是否已存在用户信息
if (req.session && req.session.user && req.session.user._id) {
console.log('从会话中获取用户信息');
// 如果数据库没有连接,直接使用会话中的用户信息
if (!isDatabaseConnected()) {
req.user = req.session.user;
return next();
}
// 确认用户在数据库中仍然存在
try {
const user = await User.findById(req.session.user._id);
if (user) {
req.user = user;
return next();
} else {
// 用户不存在,清除会话信息
req.session.user = null;
console.log('会话中的用户不存在或已被删除');
}
} catch (dbError) {
console.error('查询用户时出错:', dbError);
// 如果数据库查询出错,依然使用会话中的用户信息
req.user = req.session.user;
return next();
}
}
// 从cookie或Authorization头中获取token
let token;
if (req.cookies && req.cookies.token) {
token = req.cookies.token;
console.log('从cookie中获取到token');
} else if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
token = req.headers.authorization.split(' ')[1];
console.log('从Authorization头中获取到token');
}
if (!token) {
console.log('未找到token或会话用户信息');
return res.status(401).json({ success: false, error: '未登录或会话已过期,请重新登录' });
}
// 验证token
let decoded;
try {
// 修改这里,检查token的格式,只尝试解析有效的token
decoded = jwt.verify(token, getJwtSecret());
console.log('token验证成功,用户信息:', decoded);
// 确保decoded中有userId
if (!decoded.userId) {
// 检查是否有_id字段(旧格式)
if (decoded._id) {
decoded.userId = decoded._id;
} else {
console.error('token中没有用户ID信息');
return res.status(401).json({ success: false, error: '无效的令牌格式' });
}
}
} catch (jwtError) {
console.error('JWT验证错误:', jwtError);
if (jwtError.name === 'JsonWebTokenError') {
return res.status(401).json({ success: false, error: '无效的令牌' });
} else if (jwtError.name === 'TokenExpiredError') {
return res.status(401).json({ success: false, error: '令牌已过期,请重新登录' });
}
throw jwtError;
}
// 检查数据库连接状态
if (!isDatabaseConnected()) {
console.warn('数据库未连接,无法验证用户,但允许请求继续');
// 将解码后的用户ID添加到请求对象,但没有完整的用户信息
req.user = { _id: decoded.userId, isPartialAuth: true };
// 保存到会话
if (req.session) {
req.session.user = req.user;
}
return next();
}
// 查找用户
if (!decoded.userId) {
console.error('token解码后缺少userId字段');
return res.status(401).json({ success: false, error: '无效的令牌格式' });
}
try {
const user = await User.findById(decoded.userId);
if (!user) {
console.log('用户不存在:', decoded.userId);
return res.status(401).json({ success: false, error: '用户不存在或已被删除' });
}
// 检查用户是否被禁用
if (user.role === 'disabled') {
console.log('用户已被禁用:', user.username);
return res.status(403).json({ success: false, error: '您的账户已被禁用,请联系管理员' });
}
// 将用户信息添加到请求对象
req.user = user;
req.token = token;
// 保存到会话
if (req.session) {
req.session.user = user;
}
console.log('认证成功,用户:', user.username);
} catch (dbError) {
console.error('数据库查询错误:', dbError);
// 数据库查询失败,但允许请求继续
req.user = { _id: decoded.userId, isPartialAuth: true };
// 保存到会话
if (req.session) {
req.session.user = req.user;
}
console.warn('数据库查询失败,使用部分认证信息继续');
}
next();
} catch (error) {
console.error('认证错误:', error);
res.status(500).json({ success: false, error: '认证过程中发生错误' });
}
};
/**
* 验证用户是否为管理员的中间件
* 必须在authenticate中间件之后使用
*/
const authorizeAdmin = (req, res, next) => {
// 如果数据库未连接,无法验证管理员权限
if (!isDatabaseConnected()) {
return res.status(503).json({
message: '数据库服务不可用,无法验证管理员权限',
error: 'DATABASE_UNAVAILABLE'
});
}
if (req.user && req.user.role === 'admin') {
next();
} else {
res.status(403).json({ message: '没有管理员权限' });
}
};
/**
* 可选的认证中间件
* 如果提供了有效的令牌或会话中有用户,将用户信息添加到req.user
* 如果没有提供令牌或令牌无效,或会话中没有用户,仍然允许请求继续
*/
const optionalAuth = async (req, res, next) => {
try {
// 检查是否已经存在req.user(可能由其他中间件设置)
if (req.user) {
return next();
}
// 首先检查会话(session)中是否有用户信息
if (req.session && req.session.user) {
console.log('从会话中获取到用户信息,用户ID:', req.session.user._id);
req.user = req.session.user;
return next();
}
// 从 cookie 或 Authorization 头获取 token
const token = req.cookies.token ||
(req.header('Authorization') ? req.header('Authorization').replace('Bearer ', '') : null);
if (!token) {
// 没有令牌,继续处理请求
return next();
}
try {
// 验证 token
const decoded = jwt.verify(token, getJwtSecret());
const userId = decoded.userId || decoded._id;
if (!userId) {
console.log('token中没有用户ID信息,跳过认证');
return next();
}
console.log('token验证成功,用户ID:', userId);
// 检查数据库连接状态
if (!isDatabaseConnected()) {
console.log('可选认证: 数据库未连接,使用部分用户信息');
req.user = { _id: userId, isPartialAuth: true };
// 同时更新会话
if (req.session) {
req.session.user = req.user;
}
return next();
}
try {
// 查找用户
const user = await User.findById(userId);
if (user) {
// 将用户和令牌添加到请求对象
req.token = token;
req.user = user;
// 同时更新会话
if (req.session) {
req.session.user = user;
}
}
} catch (dbError) {
console.log('可选认证: 数据库查询失败,但继续处理请求:', dbError.message);
req.user = { _id: userId, isPartialAuth: true };
// 同时更新会话
if (req.session) {
req.session.user = req.user;
}
}
} catch (error) {
console.log('可选认证失败,但继续处理请求:', error.message);
}
next();
} catch (error) {
// 即使认证失败,也继续处理请求
console.error('可选认证错误:', error);
next();
}
};
module.exports = {
requireAuth,
authorizeAdmin,
optionalAuth,
isDatabaseConnected
};