const express = require('express'); const router = express.Router(); const jwt = require('jsonwebtoken'); const rateLimit = require('express-rate-limit'); const User = require('../models/User'); const UserRole = require('../models/UserRole'); const RolePerm = require('../models/RolePerm'); const { comparePassword } = require('../utils/password'); const loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 10, message: { success: false, message: '登录尝试过于频繁' } }); router.post('/login', loginLimiter, async (req, res) => { try { const { username, password } = req.body; const trimmedUsername = username ? username.trim() : ''; const trimmedPassword = password ? password.trim() : ''; if (!trimmedUsername || !trimmedPassword) { return res.status(400).json({ success: false, message: '用户名和密码不能为空' }); } const user = await User.findOne({ username: trimmedUsername }).select('+password'); if (!user || user.status !== 'active') { return res.status(401).json({ success: false, message: '用户名或密码错误' }); } const isMatch = await comparePassword(trimmedPassword, user.password); if (!isMatch) { return res.status(401).json({ success: false, message: '用户名或密码错误' }); } const userRole = await UserRole.findOne({ user: user._id }).populate('role'); if (!userRole) { return res.status(403).json({ success: false, message: '该用户未分配角色' }); } const rolePerms = await RolePerm.find({ role: userRole.role._id }).populate('permission'); const permissions = rolePerms.map(rp => rp.permission.permName); const token = jwt.sign( { id: user._id, username: user.username, type: user.type, role: userRole.role.roleName, permissions, jti: Math.random().toString(36) }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRES_IN || '24h' } ); res.json({ success: true, data: { id: user._id, username: user.username, name: user.name, type: user.type, role: userRole.role.roleName, roleLabel: userRole.role.roleLabel, permissions, token } }); } catch (error) { console.error('Login error:', error); res.status(500).json({ success: false, message: '服务器内部错误' }); } }); module.exports = router;