const bcrypt = require('bcryptjs'); const User = require('../models/User'); const Role = require('../models/Role'); const Menu = require('../models/Menu'); const { generateToken } = require('../middleware/auth'); const { logLogin, getClientIp } = require('../utils/logger'); // 登录 exports.login = async (req, res) => { const clientIp = getClientIp(req); const userAgent = req.headers['user-agent']; let username = req.body.username; try { const { password } = req.body; // 参数验证 if (!username || !password) { await logLogin({ username, loginType: 'login', ip: clientIp, userAgent, status: 'fail', message: '用户名和密码不能为空' }); return res.status(400).json({ code: 400, message: '用户名和密码不能为空' }); } // 查找用户 const user = await User.findOne({ where: { username }, include: [{ model: Role, as: 'role' }] }); if (!user) { await logLogin({ username, loginType: 'login', ip: clientIp, userAgent, status: 'fail', message: '用户名或密码错误' }); return res.status(401).json({ code: 401, message: '用户名或密码错误' }); } // 检查用户状态 if (user.status === 'disabled') { await logLogin({ userId: user.id, username: user.username, loginType: 'login', ip: clientIp, userAgent, status: 'fail', message: '账号已被禁用' }); return res.status(401).json({ code: 401, message: '账号已被禁用' }); } // 验证密码 const isPasswordValid = await bcrypt.compare(password, user.password); if (!isPasswordValid) { await logLogin({ userId: user.id, username: user.username, loginType: 'login', ip: clientIp, userAgent, status: 'fail', message: '用户名或密码错误' }); return res.status(401).json({ code: 401, message: '用户名或密码错误' }); } // 生成 Token const token = generateToken(user); // 获取用户菜单权限 let menus = []; // 超级管理员(isSuperAdmin为1或角色code为admin)返回所有菜单 if (user.isSuperAdmin === 1 || (user.role && user.role.code === 'admin')) { // 超级管理员返回所有菜单 const allMenus = await Menu.findAll({ where: { isDeleted: false, status: 'active', visible: 'show' }, order: [['sort', 'ASC']] }); menus = buildMenuTree(allMenus); } else if (user.roleId) { // 普通用户返回角色分配的菜单 const roleData = await Role.findByPk(user.roleId, { include: [{ model: Menu, as: 'menus', where: { isDeleted: false, status: 'active', visible: 'show' }, through: { attributes: [] } }] }); if (roleData && roleData.menus) { const sortedMenus = roleData.menus.sort((a, b) => a.sort - b.sort); menus = buildMenuTree(sortedMenus); } } // 记录登录成功日志 await logLogin({ userId: user.id, username: user.username, loginType: 'login', ip: clientIp, userAgent, status: 'success', message: '登录成功' }); // 返回用户信息和 Token res.json({ code: 200, message: '登录成功', data: { token, userInfo: { id: user.id, username: user.username, nickname: user.nickname, role: user.role }, menus } }); } catch (error) { console.error('登录错误:', error); await logLogin({ username, loginType: 'login', ip: clientIp, userAgent, status: 'fail', message: error.message }); res.status(500).json({ code: 500, message: '登录失败', error: error.message }); } }; // 登出 exports.logout = async (req, res) => { try { // 记录登出日志 const user = req.user || {}; await logLogin({ userId: user.id, username: user.username, loginType: 'logout', ip: getClientIp(req), userAgent: req.headers['user-agent'], status: 'success', message: '登出成功' }); res.json({ code: 200, message: '登出成功' }); } catch (error) { console.error('登出错误:', error); res.json({ code: 200, message: '登出成功' }); } }; // 构建菜单树 function buildMenuTree(menus, parentId = null) { return menus .filter(menu => menu.parentId === parentId) .map(menu => ({ id: menu.id, name: menu.name, code: menu.code, type: menu.type, path: menu.path, component: menu.component, icon: menu.icon, sort: menu.sort, visible: menu.visible, children: buildMenuTree(menus, menu.id) })); } // 获取当前用户信息 exports.getCurrentUser = async (req, res) => { try { // req.user 由 authMiddleware 附加 res.json({ code: 200, message: '获取成功', data: req.user }); } catch (error) { console.error('获取用户信息错误:', error); res.status(500).json({ code: 500, message: '获取用户信息失败', error: error.message }); } }; // 修改密码 exports.changePassword = async (req, res) => { try { const { oldPassword, newPassword } = req.body; const userId = req.user.id; // 参数验证 if (!oldPassword || !newPassword) { return res.status(400).json({ code: 400, message: '原密码和新密码不能为空' }); } if (newPassword.length < 6) { return res.status(400).json({ code: 400, message: '新密码长度不能少于6位' }); } // 查找用户 const user = await User.findByPk(userId); if (!user) { return res.status(404).json({ code: 404, message: '用户不存在' }); } // 验证原密码 const isPasswordValid = await bcrypt.compare(oldPassword, user.password); if (!isPasswordValid) { return res.status(400).json({ code: 400, message: '原密码错误' }); } // 加密新密码 const hashedPassword = await bcrypt.hash(newPassword, 10); // 更新密码 await user.update({ password: hashedPassword }); res.json({ code: 200, message: '密码修改成功' }); } catch (error) { console.error('修改密码错误:', error); res.status(500).json({ code: 500, message: '修改密码失败', error: error.message }); } };