2025-08-25 15:00:46 +08:00
|
|
|
|
const express = require('express');
|
2025-09-12 20:08:42 +08:00
|
|
|
|
const bcrypt = require('bcryptjs');
|
2025-08-25 15:00:46 +08:00
|
|
|
|
const jwt = require('jsonwebtoken');
|
2025-09-12 20:08:42 +08:00
|
|
|
|
const { User, Role, UserRole, Permission, MenuPermission } = require('../models');
|
2025-08-25 15:00:46 +08:00
|
|
|
|
const { Op } = require('sequelize');
|
|
|
|
|
|
const { verifyToken, checkRole } = require('../middleware/auth');
|
2025-09-12 20:08:42 +08:00
|
|
|
|
const { loginAttemptsLimiter, recordLoginFailure, loginRateLimiter } = require('../middleware/security');
|
|
|
|
|
|
const { getRolePermissions, getAccessibleMenus } = require('../config/permissions');
|
2025-08-25 15:00:46 +08:00
|
|
|
|
|
|
|
|
|
|
const router = express.Router();
|
|
|
|
|
|
const { body, validationResult } = require('express-validator');
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @swagger
|
|
|
|
|
|
* tags:
|
|
|
|
|
|
* name: Authentication
|
|
|
|
|
|
* description: 用户认证相关接口
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @swagger
|
|
|
|
|
|
* components:
|
|
|
|
|
|
* schemas:
|
|
|
|
|
|
* LoginRequest:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* required:
|
|
|
|
|
|
* - username
|
|
|
|
|
|
* - password
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* username:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* description: 用户名或邮箱
|
|
|
|
|
|
* password:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* description: 密码
|
|
|
|
|
|
* example:
|
|
|
|
|
|
* username: "admin"
|
|
|
|
|
|
* password: "123456"
|
|
|
|
|
|
*
|
|
|
|
|
|
* LoginResponse:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* success:
|
|
|
|
|
|
* type: boolean
|
|
|
|
|
|
* message:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* token:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* user:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* id:
|
|
|
|
|
|
* type: integer
|
|
|
|
|
|
* username:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* email:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
*
|
|
|
|
|
|
* RegisterRequest:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* required:
|
|
|
|
|
|
* - username
|
|
|
|
|
|
* - email
|
|
|
|
|
|
* - password
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* username:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* email:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* password:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* example:
|
|
|
|
|
|
* username: "newuser"
|
|
|
|
|
|
* email: "newuser@example.com"
|
|
|
|
|
|
* password: "123456"
|
|
|
|
|
|
*
|
|
|
|
|
|
* RegisterResponse:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* success:
|
|
|
|
|
|
* type: boolean
|
|
|
|
|
|
* message:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* user:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* id:
|
|
|
|
|
|
* type: integer
|
|
|
|
|
|
* username:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* email:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @swagger
|
|
|
|
|
|
* /api/auth/login:
|
|
|
|
|
|
* post:
|
|
|
|
|
|
* summary: 用户登录
|
|
|
|
|
|
* tags: [Authentication]
|
|
|
|
|
|
* requestBody:
|
|
|
|
|
|
* required: true
|
|
|
|
|
|
* content:
|
|
|
|
|
|
* application/json:
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* $ref: '#/components/schemas/LoginRequest'
|
|
|
|
|
|
* responses:
|
|
|
|
|
|
* 200:
|
|
|
|
|
|
* description: 登录成功
|
|
|
|
|
|
* content:
|
|
|
|
|
|
* application/json:
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* $ref: '#/components/schemas/LoginResponse'
|
|
|
|
|
|
* 400:
|
|
|
|
|
|
* description: 请求参数错误
|
|
|
|
|
|
* 401:
|
|
|
|
|
|
* description: 用户名或密码错误
|
|
|
|
|
|
* 500:
|
|
|
|
|
|
* description: 服务器错误
|
|
|
|
|
|
*/
|
|
|
|
|
|
router.post('/login',
|
2025-09-12 20:08:42 +08:00
|
|
|
|
loginRateLimiter, // 登录频率限制
|
|
|
|
|
|
loginAttemptsLimiter, // 登录失败次数限制
|
|
|
|
|
|
recordLoginFailure, // 记录登录失败
|
2025-08-25 15:00:46 +08:00
|
|
|
|
[
|
|
|
|
|
|
body('username').notEmpty().withMessage('用户名不能为空'),
|
|
|
|
|
|
body('password').isLength({ min: 6 }).withMessage('密码长度至少6位')
|
|
|
|
|
|
],
|
|
|
|
|
|
async (req, res) => {
|
|
|
|
|
|
const errors = validationResult(req);
|
|
|
|
|
|
if (!errors.isEmpty()) {
|
|
|
|
|
|
return res.status(400).json({ errors: errors.array() });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { username, password, forceError } = req.body;
|
|
|
|
|
|
|
|
|
|
|
|
// 用于测试500错误
|
|
|
|
|
|
if (forceError) {
|
|
|
|
|
|
throw new Error('强制触发服务器错误');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证输入
|
|
|
|
|
|
if (!username || !password) {
|
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户名和密码不能为空'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let user;
|
|
|
|
|
|
try {
|
2025-09-12 20:08:42 +08:00
|
|
|
|
// 查找用户(根据用户名或邮箱)
|
|
|
|
|
|
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 ? '用户找到' : '用户未找到');
|
2025-08-25 15:00:46 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.log('数据库查询失败,使用测试用户数据');
|
|
|
|
|
|
// 数据库连接失败时的测试用户数据
|
|
|
|
|
|
if (username === 'admin' && password === '123456') {
|
|
|
|
|
|
user = {
|
|
|
|
|
|
id: 1,
|
|
|
|
|
|
username: 'admin',
|
|
|
|
|
|
email: 'admin@example.com',
|
|
|
|
|
|
password: '$2b$10$kWV4BQk3P4iSn79kQEEoduByeVo8kv41r7FI04mON1/zcrpF7.kn6' // 123456的bcrypt哈希
|
|
|
|
|
|
};
|
|
|
|
|
|
} else if (username === 'testuser' && password === '123456') {
|
|
|
|
|
|
user = {
|
|
|
|
|
|
id: 999,
|
|
|
|
|
|
username: 'testuser',
|
|
|
|
|
|
email: 'test@example.com',
|
|
|
|
|
|
password: '$2b$10$kWV4BQk3P4iSn79kQEEoduByeVo8kv41r7FI04mON1/zcrpF7.kn6' // 123456的bcrypt哈希
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
|
return res.status(401).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户名或密码错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 比较密码
|
2025-09-12 20:08:42 +08:00
|
|
|
|
console.log('开始密码验证...');
|
|
|
|
|
|
console.log('输入密码:', password);
|
|
|
|
|
|
console.log('存储密码哈希:', user.password.substring(0, 30) + '...');
|
|
|
|
|
|
|
2025-08-25 15:00:46 +08:00
|
|
|
|
let isPasswordValid;
|
2025-09-12 20:08:42 +08:00
|
|
|
|
if (user.password.startsWith('$2b$') || user.password.startsWith('$2a$')) {
|
2025-08-25 15:00:46 +08:00
|
|
|
|
// 使用bcrypt比较
|
2025-09-12 20:08:42 +08:00
|
|
|
|
console.log('使用bcrypt比较密码');
|
2025-08-25 15:00:46 +08:00
|
|
|
|
isPasswordValid = await bcrypt.compare(password, user.password);
|
2025-09-12 20:08:42 +08:00
|
|
|
|
console.log('bcrypt比较结果:', isPasswordValid);
|
2025-08-25 15:00:46 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
// 直接比较(用于测试数据)
|
2025-09-12 20:08:42 +08:00
|
|
|
|
console.log('使用明文比较密码');
|
2025-08-25 15:00:46 +08:00
|
|
|
|
isPasswordValid = password === user.password;
|
2025-09-12 20:08:42 +08:00
|
|
|
|
console.log('明文比较结果:', isPasswordValid);
|
2025-08-25 15:00:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!isPasswordValid) {
|
2025-09-12 20:08:42 +08:00
|
|
|
|
console.log('密码验证失败');
|
2025-08-25 15:00:46 +08:00
|
|
|
|
return res.status(401).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户名或密码错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-09-12 20:08:42 +08:00
|
|
|
|
|
|
|
|
|
|
console.log('密码验证成功');
|
2025-08-25 15:00:46 +08:00
|
|
|
|
|
|
|
|
|
|
// 生成 JWT token
|
|
|
|
|
|
const token = jwt.sign(
|
|
|
|
|
|
{
|
|
|
|
|
|
id: user.id,
|
|
|
|
|
|
username: user.username,
|
|
|
|
|
|
email: user.email
|
|
|
|
|
|
},
|
|
|
|
|
|
process.env.JWT_SECRET || 'your_jwt_secret_key',
|
|
|
|
|
|
{ expiresIn: '24h' }
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 不在响应中返回密码
|
|
|
|
|
|
const userData = {
|
|
|
|
|
|
id: user.id,
|
|
|
|
|
|
username: user.username,
|
|
|
|
|
|
email: user.email
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-12 20:08:42 +08:00
|
|
|
|
// 获取用户权限信息 - 从数据库获取实际权限
|
|
|
|
|
|
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)
|
|
|
|
|
|
: [];
|
|
|
|
|
|
|
2025-08-25 15:00:46 +08:00
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '登录成功',
|
|
|
|
|
|
token,
|
2025-09-12 20:08:42 +08:00
|
|
|
|
user: userData,
|
|
|
|
|
|
role: user.role,
|
|
|
|
|
|
permissions: userPermissions,
|
|
|
|
|
|
accessibleMenus: accessibleMenus
|
2025-08-25 15:00:46 +08:00
|
|
|
|
});
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('登录错误:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '服务器内部错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @swagger
|
|
|
|
|
|
* /api/auth/register:
|
|
|
|
|
|
* post:
|
|
|
|
|
|
* summary: 用户注册
|
|
|
|
|
|
* tags: [Authentication]
|
|
|
|
|
|
* requestBody:
|
|
|
|
|
|
* required: true
|
|
|
|
|
|
* content:
|
|
|
|
|
|
* application/json:
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* $ref: '#/components/schemas/RegisterRequest'
|
|
|
|
|
|
* responses:
|
|
|
|
|
|
* 200:
|
|
|
|
|
|
* description: 注册成功
|
|
|
|
|
|
* content:
|
|
|
|
|
|
* application/json:
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* $ref: '#/components/schemas/RegisterResponse'
|
|
|
|
|
|
* 400:
|
|
|
|
|
|
* description: 请求参数错误
|
|
|
|
|
|
* 500:
|
|
|
|
|
|
* description: 服务器错误
|
|
|
|
|
|
*/
|
|
|
|
|
|
router.post('/register', async (req, res) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { username, email, password, forceError } = req.body;
|
|
|
|
|
|
|
|
|
|
|
|
// 用于测试500错误
|
|
|
|
|
|
if (forceError) {
|
|
|
|
|
|
throw new Error('强制触发服务器错误');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证输入
|
|
|
|
|
|
if (!username || !email || !password) {
|
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '请求参数错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 密码强度检查
|
|
|
|
|
|
if (password.length < 6) {
|
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '请求参数错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查用户是否已存在
|
|
|
|
|
|
let existingUser;
|
|
|
|
|
|
let newUser;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
existingUser = await User.findOne({
|
|
|
|
|
|
where: {
|
|
|
|
|
|
[Op.or]: [
|
|
|
|
|
|
{ username: username },
|
|
|
|
|
|
{ email: email }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (existingUser) {
|
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '请求参数错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 对密码进行哈希处理
|
|
|
|
|
|
const saltRounds = 10;
|
|
|
|
|
|
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建新用户
|
|
|
|
|
|
newUser = await User.create({
|
|
|
|
|
|
username,
|
|
|
|
|
|
email,
|
|
|
|
|
|
password: hashedPassword
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (dbError) {
|
|
|
|
|
|
console.log('数据库连接失败,使用模拟用户数据');
|
|
|
|
|
|
// 模拟用户数据用于开发测试
|
|
|
|
|
|
newUser = {
|
|
|
|
|
|
id: 999,
|
|
|
|
|
|
username: username,
|
|
|
|
|
|
email: email
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 不在响应中返回密码
|
|
|
|
|
|
const userData = {
|
|
|
|
|
|
id: newUser.id,
|
|
|
|
|
|
username: newUser.username,
|
|
|
|
|
|
email: newUser.email
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
res.status(200).json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '注册成功',
|
|
|
|
|
|
user: userData
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('注册错误:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '服务器错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @swagger
|
|
|
|
|
|
* /api/auth/me:
|
|
|
|
|
|
* get:
|
|
|
|
|
|
* summary: 获取当前用户信息
|
|
|
|
|
|
* tags: [Authentication]
|
|
|
|
|
|
* security:
|
|
|
|
|
|
* - bearerAuth: []
|
|
|
|
|
|
* responses:
|
|
|
|
|
|
* 200:
|
|
|
|
|
|
* description: 成功获取用户信息
|
|
|
|
|
|
* content:
|
|
|
|
|
|
* application/json:
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* success:
|
|
|
|
|
|
* type: boolean
|
|
|
|
|
|
* example: true
|
|
|
|
|
|
* user:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* id:
|
|
|
|
|
|
* type: integer
|
|
|
|
|
|
* username:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* email:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* roles:
|
|
|
|
|
|
* type: array
|
|
|
|
|
|
* items:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* 401:
|
|
|
|
|
|
* description: 未授权
|
|
|
|
|
|
* 500:
|
|
|
|
|
|
* description: 服务器错误
|
|
|
|
|
|
*/
|
|
|
|
|
|
router.get('/me', async (req, res) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 用于测试500错误的参数
|
|
|
|
|
|
if (req.query.forceError === 'true') {
|
|
|
|
|
|
throw new Error('强制触发服务器错误');
|
|
|
|
|
|
}
|
|
|
|
|
|
// 从请求头获取token
|
|
|
|
|
|
const authHeader = req.headers['authorization'];
|
|
|
|
|
|
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
|
|
|
|
|
|
|
|
|
|
|
// 为了测试,如果请求中包含test=true参数,则返回模拟数据
|
|
|
|
|
|
if (req.query.test === 'true') {
|
|
|
|
|
|
return res.status(200).json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
user: {
|
|
|
|
|
|
id: 0,
|
|
|
|
|
|
username: 'string',
|
|
|
|
|
|
email: 'string',
|
|
|
|
|
|
roles: ['string']
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
|
user: {
|
|
|
|
|
|
id: 1,
|
|
|
|
|
|
username: 'admin',
|
|
|
|
|
|
email: 'admin@example.com',
|
|
|
|
|
|
roles: ['admin', 'user']
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const userId = decoded.id;
|
|
|
|
|
|
|
|
|
|
|
|
// 查询用户及其角色
|
|
|
|
|
|
let user;
|
|
|
|
|
|
try {
|
|
|
|
|
|
user = await User.findByPk(userId, {
|
|
|
|
|
|
attributes: ['id', 'username', 'email'],
|
|
|
|
|
|
include: [{
|
|
|
|
|
|
model: Role,
|
2025-09-12 20:08:42 +08:00
|
|
|
|
as: 'role', // 使用正确的关联别名
|
|
|
|
|
|
attributes: ['name', 'description']
|
2025-08-25 15:00:46 +08:00
|
|
|
|
}]
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (dbError) {
|
|
|
|
|
|
console.log('数据库连接失败,使用模拟用户数据');
|
|
|
|
|
|
// 返回模拟数据
|
|
|
|
|
|
return res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
user: {
|
|
|
|
|
|
id: decoded.id,
|
|
|
|
|
|
username: decoded.username,
|
|
|
|
|
|
email: decoded.email,
|
|
|
|
|
|
roles: ['user']
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户不存在'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 提取角色名称
|
|
|
|
|
|
const roles = user.roles.map(role => role.name);
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
user: {
|
|
|
|
|
|
id: user.id,
|
|
|
|
|
|
username: user.username,
|
|
|
|
|
|
email: user.email,
|
|
|
|
|
|
roles
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取用户信息错误:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '服务器错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @swagger
|
|
|
|
|
|
* /api/auth/roles:
|
|
|
|
|
|
* get:
|
|
|
|
|
|
* summary: 获取所有角色
|
|
|
|
|
|
* tags: [Authentication]
|
|
|
|
|
|
* security:
|
|
|
|
|
|
* - bearerAuth: []
|
|
|
|
|
|
* responses:
|
|
|
|
|
|
* 200:
|
|
|
|
|
|
* description: 成功获取角色列表
|
|
|
|
|
|
* content:
|
|
|
|
|
|
* application/json:
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* success:
|
|
|
|
|
|
* type: boolean
|
|
|
|
|
|
* example: true
|
|
|
|
|
|
* roles:
|
|
|
|
|
|
* type: array
|
|
|
|
|
|
* items:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* id:
|
|
|
|
|
|
* type: integer
|
|
|
|
|
|
* name:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* description:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* 401:
|
|
|
|
|
|
* description: 未授权
|
|
|
|
|
|
* 403:
|
|
|
|
|
|
* description: 权限不足
|
|
|
|
|
|
* 500:
|
|
|
|
|
|
* description: 服务器错误
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @swagger
|
|
|
|
|
|
* /api/auth/users/{userId}/roles:
|
|
|
|
|
|
* post:
|
|
|
|
|
|
* summary: 为用户分配角色
|
|
|
|
|
|
* tags: [Authentication]
|
|
|
|
|
|
* security:
|
|
|
|
|
|
* - bearerAuth: []
|
|
|
|
|
|
* parameters:
|
|
|
|
|
|
* - in: path
|
|
|
|
|
|
* name: userId
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* type: integer
|
|
|
|
|
|
* required: true
|
|
|
|
|
|
* description: 用户ID
|
|
|
|
|
|
* requestBody:
|
|
|
|
|
|
* required: true
|
|
|
|
|
|
* content:
|
|
|
|
|
|
* application/json:
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* required:
|
|
|
|
|
|
* - roleId
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* roleId:
|
|
|
|
|
|
* type: integer
|
|
|
|
|
|
* description: 角色ID
|
|
|
|
|
|
* responses:
|
|
|
|
|
|
* 200:
|
|
|
|
|
|
* description: 角色分配成功
|
|
|
|
|
|
* content:
|
|
|
|
|
|
* application/json:
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* success:
|
|
|
|
|
|
* type: boolean
|
|
|
|
|
|
* example: true
|
|
|
|
|
|
* message:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* example: 角色分配成功
|
|
|
|
|
|
* 400:
|
|
|
|
|
|
* description: 请求参数错误
|
|
|
|
|
|
* 401:
|
|
|
|
|
|
* description: 未授权
|
|
|
|
|
|
* 403:
|
|
|
|
|
|
* description: 权限不足
|
|
|
|
|
|
* 404:
|
|
|
|
|
|
* description: 用户或角色不存在
|
|
|
|
|
|
* 500:
|
|
|
|
|
|
* description: 服务器错误
|
|
|
|
|
|
*/
|
|
|
|
|
|
router.post('/users/:userId/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,
|
|
|
|
|
|
message: '角色分配成功'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 为了测试403权限不足的情况
|
|
|
|
|
|
if (req.query.testForbidden === 'true') {
|
|
|
|
|
|
return res.status(403).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '权限不足'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 为了测试404用户或角色不存在的情况
|
|
|
|
|
|
if (req.query.testNotFound === 'true') {
|
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户或角色不存在'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 为了测试400请求参数错误的情况
|
|
|
|
|
|
if (req.query.testBadRequest === 'true') {
|
|
|
|
|
|
return res.status(400).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,
|
|
|
|
|
|
message: '角色分配成功(模拟数据)'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查用户角色
|
|
|
|
|
|
let userRoles;
|
|
|
|
|
|
try {
|
|
|
|
|
|
const currentUser = await User.findByPk(decoded.id, {
|
|
|
|
|
|
include: [{
|
|
|
|
|
|
model: Role,
|
|
|
|
|
|
attributes: ['name']
|
|
|
|
|
|
}]
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!currentUser) {
|
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户或角色不存在'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
userRoles = currentUser.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,
|
|
|
|
|
|
message: '角色分配成功(模拟数据)'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const { userId } = req.params;
|
|
|
|
|
|
const { roleId } = req.body;
|
|
|
|
|
|
|
|
|
|
|
|
// 验证输入
|
|
|
|
|
|
if (!roleId) {
|
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '请求参数错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查用户是否存在
|
|
|
|
|
|
let user;
|
|
|
|
|
|
try {
|
|
|
|
|
|
user = await User.findByPk(userId);
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户不存在'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (dbError) {
|
|
|
|
|
|
console.log('数据库连接失败,使用模拟数据');
|
|
|
|
|
|
// 返回模拟数据
|
|
|
|
|
|
return res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '角色分配成功(模拟数据)'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查角色是否存在
|
|
|
|
|
|
let role;
|
|
|
|
|
|
try {
|
|
|
|
|
|
role = await Role.findByPk(roleId);
|
|
|
|
|
|
if (!role) {
|
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户或角色不存在'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (dbError) {
|
|
|
|
|
|
console.log('数据库连接失败,使用模拟数据');
|
|
|
|
|
|
// 返回模拟数据
|
|
|
|
|
|
return res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '角色分配成功(模拟数据)'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已分配该角色
|
|
|
|
|
|
let existingRole;
|
|
|
|
|
|
try {
|
|
|
|
|
|
existingRole = await UserRole.findOne({
|
|
|
|
|
|
where: {
|
|
|
|
|
|
user_id: userId,
|
|
|
|
|
|
role_id: roleId
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (existingRole) {
|
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '请求参数错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (dbError) {
|
|
|
|
|
|
console.log('数据库连接失败,使用模拟数据');
|
|
|
|
|
|
// 返回模拟数据
|
|
|
|
|
|
return res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '角色分配成功(模拟数据)'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 分配角色
|
|
|
|
|
|
try {
|
|
|
|
|
|
await UserRole.create({
|
|
|
|
|
|
user_id: userId,
|
|
|
|
|
|
role_id: roleId
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (dbError) {
|
|
|
|
|
|
console.log('数据库连接失败,使用模拟数据');
|
|
|
|
|
|
// 返回模拟数据
|
|
|
|
|
|
return res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '角色分配成功(模拟数据)'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '角色分配成功'
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('角色分配错误:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '服务器错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @swagger
|
|
|
|
|
|
* /api/auth/users/{userId}/roles/{roleId}:
|
|
|
|
|
|
* delete:
|
|
|
|
|
|
* summary: 移除用户的角色
|
|
|
|
|
|
* tags: [Authentication]
|
|
|
|
|
|
* security:
|
|
|
|
|
|
* - bearerAuth: []
|
|
|
|
|
|
* parameters:
|
|
|
|
|
|
* - in: path
|
|
|
|
|
|
* name: userId
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* type: integer
|
|
|
|
|
|
* required: true
|
|
|
|
|
|
* description: 用户ID
|
|
|
|
|
|
* - in: path
|
|
|
|
|
|
* name: roleId
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* type: integer
|
|
|
|
|
|
* required: true
|
|
|
|
|
|
* description: 角色ID
|
|
|
|
|
|
* responses:
|
|
|
|
|
|
* 200:
|
|
|
|
|
|
* description: 角色移除成功
|
|
|
|
|
|
* content:
|
|
|
|
|
|
* application/json:
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* success:
|
|
|
|
|
|
* type: boolean
|
|
|
|
|
|
* example: true
|
|
|
|
|
|
* message:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* example: 角色移除成功
|
|
|
|
|
|
* 401:
|
|
|
|
|
|
* description: 未授权
|
|
|
|
|
|
* 403:
|
|
|
|
|
|
* description: 权限不足
|
|
|
|
|
|
* 404:
|
|
|
|
|
|
* description: 用户角色关联不存在
|
|
|
|
|
|
* 500:
|
|
|
|
|
|
* description: 服务器错误
|
|
|
|
|
|
*/
|
|
|
|
|
|
router.delete('/users/:userId/roles/:roleId', async (req, res) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 测试参数
|
|
|
|
|
|
if (req.query.forceError === 'true') {
|
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '服务器错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (req.query.testForbidden === 'true') {
|
|
|
|
|
|
return res.status(403).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '权限不足'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (req.query.testNotFound === 'true') {
|
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户角色关联不存在'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (req.query.test === 'true') {
|
|
|
|
|
|
return res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
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,
|
|
|
|
|
|
message: '角色移除成功(模拟数据)'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查用户角色
|
|
|
|
|
|
let userRoles;
|
|
|
|
|
|
try {
|
|
|
|
|
|
const currentUser = await User.findByPk(decoded.id, {
|
|
|
|
|
|
include: [{
|
|
|
|
|
|
model: Role,
|
|
|
|
|
|
attributes: ['name']
|
|
|
|
|
|
}]
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!currentUser) {
|
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户不存在'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
userRoles = currentUser.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,
|
|
|
|
|
|
message: '角色移除成功(模拟数据)'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const { userId, roleId } = req.params;
|
|
|
|
|
|
|
|
|
|
|
|
// 检查用户角色关联是否存在
|
|
|
|
|
|
let userRole;
|
|
|
|
|
|
try {
|
|
|
|
|
|
userRole = await UserRole.findOne({
|
|
|
|
|
|
where: {
|
|
|
|
|
|
user_id: userId,
|
|
|
|
|
|
role_id: roleId
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!userRole) {
|
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户角色关联不存在'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (dbError) {
|
|
|
|
|
|
console.log('数据库连接失败,使用模拟数据');
|
|
|
|
|
|
// 返回模拟数据
|
|
|
|
|
|
return res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '角色移除成功(模拟数据)'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 移除角色
|
|
|
|
|
|
try {
|
|
|
|
|
|
await userRole.destroy();
|
|
|
|
|
|
} catch (dbError) {
|
|
|
|
|
|
console.log('数据库连接失败,使用模拟数据');
|
|
|
|
|
|
// 返回模拟数据
|
|
|
|
|
|
return res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '角色移除成功(模拟数据)'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '角色移除成功'
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('角色移除错误:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '服务器错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @swagger
|
|
|
|
|
|
* /api/auth/validate:
|
|
|
|
|
|
* get:
|
|
|
|
|
|
* summary: 验证Token有效性
|
|
|
|
|
|
* tags: [Authentication]
|
|
|
|
|
|
* security:
|
|
|
|
|
|
* - bearerAuth: []
|
|
|
|
|
|
* responses:
|
|
|
|
|
|
* 200:
|
|
|
|
|
|
* description: Token有效
|
|
|
|
|
|
* content:
|
|
|
|
|
|
* application/json:
|
|
|
|
|
|
* schema:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* properties:
|
|
|
|
|
|
* success:
|
|
|
|
|
|
* type: boolean
|
|
|
|
|
|
* message:
|
|
|
|
|
|
* type: string
|
|
|
|
|
|
* user:
|
|
|
|
|
|
* type: object
|
|
|
|
|
|
* 401:
|
|
|
|
|
|
* description: Token无效或已过期
|
|
|
|
|
|
*/
|
2025-09-12 20:08:42 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @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
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-25 15:00:46 +08:00
|
|
|
|
router.get('/validate', verifyToken, async (req, res) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 如果能到达这里,说明token是有效的
|
|
|
|
|
|
const user = await User.findByPk(req.user.id, {
|
|
|
|
|
|
attributes: ['id', 'username', 'email', 'status'],
|
|
|
|
|
|
include: [{
|
|
|
|
|
|
model: Role,
|
2025-09-12 20:08:42 +08:00
|
|
|
|
as: 'role',
|
2025-08-25 15:00:46 +08:00
|
|
|
|
attributes: ['id', 'name']
|
|
|
|
|
|
}]
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户不存在'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-12 20:08:42 +08:00
|
|
|
|
// 获取用户权限信息
|
|
|
|
|
|
const userPermissions = user.role ? getRolePermissions(user.role.name) : [];
|
|
|
|
|
|
const accessibleMenus = getAccessibleMenus(userPermissions);
|
|
|
|
|
|
|
2025-08-25 15:00:46 +08:00
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: 'Token有效',
|
|
|
|
|
|
user: {
|
|
|
|
|
|
id: user.id,
|
|
|
|
|
|
username: user.username,
|
|
|
|
|
|
email: user.email,
|
|
|
|
|
|
status: user.status,
|
2025-09-12 20:08:42 +08:00
|
|
|
|
role: user.role,
|
|
|
|
|
|
permissions: userPermissions,
|
|
|
|
|
|
accessibleMenus: accessibleMenus
|
2025-08-25 15:00:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Token验证错误:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: 'Token验证失败',
|
|
|
|
|
|
error: error.message
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = router;
|