修改管理后台

This commit is contained in:
shenquanyi
2025-09-12 20:08:42 +08:00
parent 39d61c6f9b
commit 80a24c2d60
286 changed files with 75316 additions and 9452 deletions

View File

@@ -1,9 +1,11 @@
const express = require('express');
const bcrypt = require('bcrypt');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { User, Role, UserRole } = require('../models');
const { User, Role, UserRole, Permission, MenuPermission } = require('../models');
const { Op } = require('sequelize');
const { verifyToken, checkRole } = require('../middleware/auth');
const { loginAttemptsLimiter, recordLoginFailure, loginRateLimiter } = require('../middleware/security');
const { getRolePermissions, getAccessibleMenus } = require('../config/permissions');
const router = express.Router();
const { body, validationResult } = require('express-validator');
@@ -117,6 +119,9 @@ const { body, validationResult } = require('express-validator');
* description: 服务器错误
*/
router.post('/login',
loginRateLimiter, // 登录频率限制
loginAttemptsLimiter, // 登录失败次数限制
recordLoginFailure, // 记录登录失败
[
body('username').notEmpty().withMessage('用户名不能为空'),
body('password').isLength({ min: 6 }).withMessage('密码长度至少6位')
@@ -145,15 +150,22 @@ router.post('/login',
let user;
try {
// 查找用户(根据用户名或邮箱)
user = await User.findOne({
where: {
[Op.or]: [
{ username: username },
{ email: username }
]
}
});
// 查找用户(根据用户名或邮箱)
console.log('查找用户:', username);
user = await User.findOne({
where: {
[Op.or]: [
{ username: username },
{ email: username }
]
},
include: [{
model: Role,
as: 'role',
attributes: ['id', 'name', 'description']
}]
});
console.log('查询结果:', user ? '用户找到' : '用户未找到');
} catch (error) {
console.log('数据库查询失败,使用测试用户数据');
// 数据库连接失败时的测试用户数据
@@ -182,21 +194,32 @@ router.post('/login',
}
// 比较密码
console.log('开始密码验证...');
console.log('输入密码:', password);
console.log('存储密码哈希:', user.password.substring(0, 30) + '...');
let isPasswordValid;
if (user.password.startsWith('$2b$')) {
if (user.password.startsWith('$2b$') || user.password.startsWith('$2a$')) {
// 使用bcrypt比较
console.log('使用bcrypt比较密码');
isPasswordValid = await bcrypt.compare(password, user.password);
console.log('bcrypt比较结果:', isPasswordValid);
} else {
// 直接比较(用于测试数据)
console.log('使用明文比较密码');
isPasswordValid = password === user.password;
console.log('明文比较结果:', isPasswordValid);
}
if (!isPasswordValid) {
console.log('密码验证失败');
return res.status(401).json({
success: false,
message: '用户名或密码错误'
});
}
console.log('密码验证成功');
// 生成 JWT token
const token = jwt.sign(
@@ -216,11 +239,43 @@ router.post('/login',
email: user.email
};
// 获取用户权限信息 - 从数据库获取实际权限
const userWithPermissions = await User.findByPk(user.id, {
include: [{
model: Role,
as: 'role',
include: [{
model: Permission,
as: 'permissions',
through: { attributes: [] },
attributes: ['permission_key']
}, {
model: MenuPermission,
as: 'menuPermissions',
through: { attributes: [] },
attributes: ['menu_key']
}]
}]
});
// 从数据库获取功能权限
const userPermissions = userWithPermissions.role && userWithPermissions.role.permissions
? userWithPermissions.role.permissions.map(p => p.permission_key)
: [];
// 从数据库获取菜单权限
const accessibleMenus = userWithPermissions.role && userWithPermissions.role.menuPermissions
? userWithPermissions.role.menuPermissions.map(m => m.menu_key)
: [];
res.json({
success: true,
message: '登录成功',
token,
user: userData
user: userData,
role: user.role,
permissions: userPermissions,
accessibleMenus: accessibleMenus
});
} catch (error) {
console.error('登录错误:', error);
@@ -443,9 +498,8 @@ router.get('/me', async (req, res) => {
attributes: ['id', 'username', 'email'],
include: [{
model: Role,
as: 'roles', // 添加as属性指定关联别名
attributes: ['name', 'description'],
through: { attributes: [] } // 不包含中间表字段
as: 'role', // 使用正确的关联别名
attributes: ['name', 'description']
}]
});
} catch (dbError) {
@@ -527,135 +581,7 @@ router.get('/me', async (req, res) => {
* 500:
* description: 服务器错误
*/
router.get('/roles', async (req, res) => {
try {
// 用于测试500错误的参数
if (req.query.forceError === 'true') {
throw new Error('强制触发服务器错误');
}
// 为了测试如果请求中包含test=true参数则返回模拟数据
if (req.query.test === 'true') {
return res.status(200).json({
success: true,
roles: [
{ id: 0, name: 'string', description: 'string' }
]
});
}
// 为了测试403权限不足的情况
if (req.query.testForbidden === 'true') {
return res.status(403).json({
success: false,
message: '权限不足'
});
}
// 从请求头获取token
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (!token) {
return res.status(401).json({
success: false,
message: '未授权'
});
}
// 验证token
let decoded;
try {
decoded = jwt.verify(token, process.env.JWT_SECRET || 'your_jwt_secret_key');
} catch (err) {
if (err instanceof jwt.JsonWebTokenError || err instanceof jwt.TokenExpiredError) {
return res.status(401).json({
success: false,
message: '未授权'
});
}
// 如果是其他错误,返回模拟数据
return res.json({
success: true,
roles: [
{ id: 1, name: 'admin', description: '管理员' },
{ id: 2, name: 'user', description: '普通用户' },
{ id: 3, name: 'guest', description: '访客' }
]
});
}
// 检查用户角色
let userRoles;
try {
const user = await User.findByPk(decoded.id, {
include: [{
model: Role,
as: 'roles', // 添加as属性指定关联别名
attributes: ['name']
}]
});
if (!user) {
return res.status(404).json({
success: false,
message: '用户或角色不存在'
});
}
userRoles = user.roles.map(role => role.name);
// 检查用户是否具有admin角色
if (!userRoles.includes('admin')) {
return res.status(403).json({
success: false,
message: '权限不足'
});
}
} catch (dbError) {
console.log('数据库连接失败,使用模拟数据');
// 返回模拟数据
return res.json({
success: true,
roles: [
{ id: 1, name: 'admin', description: '管理员' },
{ id: 2, name: 'user', description: '普通用户' },
{ id: 3, name: 'guest', description: '访客' }
]
});
}
// 获取所有角色
let roles;
try {
roles = await Role.findAll({
attributes: ['id', 'name', 'description']
});
} catch (dbError) {
console.log('数据库连接失败,使用模拟数据');
// 返回模拟数据
return res.json({
success: true,
roles: [
{ id: 1, name: 'admin', description: '管理员' },
{ id: 2, name: 'user', description: '普通用户' },
{ id: 3, name: 'guest', description: '访客' }
]
});
}
res.json({
success: true,
roles
});
} catch (error) {
console.error('获取角色列表错误:', error);
res.status(500).json({
success: false,
message: '服务器错误'
});
}
});
/**
* @swagger
@@ -1131,6 +1057,58 @@ router.delete('/users/:userId/roles/:roleId', async (req, res) => {
* 401:
* description: Token无效或已过期
*/
/**
* @swagger
* /api/auth/roles:
* get:
* summary: 获取所有角色列表
* tags: [Authentication]
* responses:
* 200:
* description: 获取角色列表成功
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* data:
* type: array
* items:
* type: object
* properties:
* id:
* type: integer
* name:
* type: string
* description:
* type: string
* 500:
* description: 服务器错误
*/
router.get('/roles', async (req, res) => {
try {
const roles = await Role.findAll({
attributes: ['id', 'name', 'description'],
order: [['id', 'ASC']]
});
res.json({
success: true,
data: roles,
roles: roles // 兼容性,同时提供两种格式
});
} catch (error) {
console.error('获取角色列表错误:', error);
res.status(500).json({
success: false,
message: '获取角色列表失败',
error: error.message
});
}
});
router.get('/validate', verifyToken, async (req, res) => {
try {
// 如果能到达这里说明token是有效的
@@ -1138,7 +1116,7 @@ router.get('/validate', verifyToken, async (req, res) => {
attributes: ['id', 'username', 'email', 'status'],
include: [{
model: Role,
as: 'roles',
as: 'role',
attributes: ['id', 'name']
}]
});
@@ -1150,6 +1128,10 @@ router.get('/validate', verifyToken, async (req, res) => {
});
}
// 获取用户权限信息
const userPermissions = user.role ? getRolePermissions(user.role.name) : [];
const accessibleMenus = getAccessibleMenus(userPermissions);
res.json({
success: true,
message: 'Token有效',
@@ -1158,7 +1140,9 @@ router.get('/validate', verifyToken, async (req, res) => {
username: user.username,
email: user.email,
status: user.status,
roles: user.roles
role: user.role,
permissions: userPermissions,
accessibleMenus: accessibleMenus
}
});
} catch (error) {