完善保险前后端、养殖端小程序
This commit is contained in:
@@ -17,11 +17,15 @@ app.use(cors({
|
||||
credentials: true
|
||||
}));
|
||||
|
||||
// 速率限制
|
||||
// 速率限制 - 开发环境下放宽限制
|
||||
const limiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15分钟
|
||||
max: 100, // 限制每个IP每15分钟最多100个请求
|
||||
message: '请求过于频繁,请稍后再试'
|
||||
windowMs: 1 * 60 * 1000, // 1分钟
|
||||
max: 1000, // 限制每个IP每1分钟最多1000个请求
|
||||
message: '请求过于频繁,请稍后再试',
|
||||
skip: (req) => {
|
||||
// 在开发环境下跳过限流
|
||||
return process.env.NODE_ENV === 'development';
|
||||
}
|
||||
});
|
||||
app.use(limiter);
|
||||
|
||||
@@ -56,6 +60,7 @@ app.use('/api/insurance-types', require('../routes/insuranceTypes'));
|
||||
app.use('/api/policies', require('../routes/policies'));
|
||||
app.use('/api/claims', require('../routes/claims'));
|
||||
app.use('/api/system', require('../routes/system'));
|
||||
app.use('/api/dashboard', require('../routes/dashboard'));
|
||||
app.use('/api/operation-logs', require('../routes/operationLogs'));
|
||||
app.use('/api/menus', require('../routes/menus'));
|
||||
app.use('/api/data-warehouse', require('../routes/dataWarehouse'));
|
||||
@@ -73,6 +78,10 @@ app.use('/api/livestock-claims', require('../routes/livestockClaims'));
|
||||
app.use('/api/devices', require('../routes/devices'));
|
||||
app.use('/api/device-alerts', require('../routes/deviceAlerts'));
|
||||
|
||||
// 权限管理相关路由
|
||||
app.use('/api/permissions', require('../routes/permissions'));
|
||||
app.use('/api/role-permissions', require('../routes/rolePermissions'));
|
||||
|
||||
// API文档路由
|
||||
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
|
||||
explorer: true,
|
||||
|
||||
191
insurance_backend/src/middleware/permissionMiddleware.js
Normal file
191
insurance_backend/src/middleware/permissionMiddleware.js
Normal file
@@ -0,0 +1,191 @@
|
||||
const PermissionService = require('../services/permissionService');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
/**
|
||||
* 权限检查中间件
|
||||
* @param {string|string[]} requiredPermissions - 必需的权限代码(单个或数组)
|
||||
* @param {string} checkType - 检查类型:'any'(任意一个)或 'all'(全部)
|
||||
* @returns {Function} Express中间件函数
|
||||
*/
|
||||
const requirePermission = (requiredPermissions, checkType = 'any') => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
// 从请求头获取token
|
||||
const token = req.headers.authorization?.replace('Bearer ', '');
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '未提供认证令牌'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证token并获取用户信息
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||
const userId = decoded.userId;
|
||||
|
||||
if (!userId) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '无效的认证令牌'
|
||||
});
|
||||
}
|
||||
|
||||
// 确保权限是数组格式
|
||||
const permissions = Array.isArray(requiredPermissions)
|
||||
? requiredPermissions
|
||||
: [requiredPermissions];
|
||||
|
||||
let hasPermission = false;
|
||||
|
||||
// 根据检查类型进行权限验证
|
||||
if (checkType === 'all') {
|
||||
hasPermission = await PermissionService.checkUserAllPermissions(userId, permissions);
|
||||
} else {
|
||||
hasPermission = await PermissionService.checkUserAnyPermission(userId, permissions);
|
||||
}
|
||||
|
||||
if (!hasPermission) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: '权限不足,无法访问此资源',
|
||||
requiredPermissions: permissions
|
||||
});
|
||||
}
|
||||
|
||||
// 将用户ID添加到请求对象中,供后续使用
|
||||
req.userId = userId;
|
||||
next();
|
||||
} catch (error) {
|
||||
console.error('权限检查中间件错误:', error);
|
||||
|
||||
if (error.name === 'JsonWebTokenError') {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '无效的认证令牌'
|
||||
});
|
||||
}
|
||||
|
||||
if (error.name === 'TokenExpiredError') {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '认证令牌已过期'
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '权限检查失败'
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查单个权限的中间件
|
||||
* @param {string} permission - 权限代码
|
||||
* @returns {Function} Express中间件函数
|
||||
*/
|
||||
const requireSinglePermission = (permission) => {
|
||||
return requirePermission(permission, 'any');
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查多个权限中任意一个的中间件
|
||||
* @param {string[]} permissions - 权限代码数组
|
||||
* @returns {Function} Express中间件函数
|
||||
*/
|
||||
const requireAnyPermission = (permissions) => {
|
||||
return requirePermission(permissions, 'any');
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查多个权限全部具备的中间件
|
||||
* @param {string[]} permissions - 权限代码数组
|
||||
* @returns {Function} Express中间件函数
|
||||
*/
|
||||
const requireAllPermissions = (permissions) => {
|
||||
return requirePermission(permissions, 'all');
|
||||
};
|
||||
|
||||
/**
|
||||
* 管理员权限检查中间件
|
||||
* @returns {Function} Express中间件函数
|
||||
*/
|
||||
const requireAdmin = () => {
|
||||
return requireSinglePermission('system:admin');
|
||||
};
|
||||
|
||||
/**
|
||||
* 超级管理员权限检查中间件
|
||||
* @returns {Function} Express中间件函数
|
||||
*/
|
||||
const requireSuperAdmin = () => {
|
||||
return requireSinglePermission('system:super_admin');
|
||||
};
|
||||
|
||||
/**
|
||||
* 权限检查装饰器(用于控制器方法)
|
||||
* @param {string|string[]} permissions - 权限代码
|
||||
* @param {string} checkType - 检查类型
|
||||
* @returns {Function} 装饰器函数
|
||||
*/
|
||||
const withPermission = (permissions, checkType = 'any') => {
|
||||
return (target, propertyKey, descriptor) => {
|
||||
const originalMethod = descriptor.value;
|
||||
|
||||
descriptor.value = async function(req, res, next) {
|
||||
try {
|
||||
const middleware = requirePermission(permissions, checkType);
|
||||
await new Promise((resolve, reject) => {
|
||||
middleware(req, res, (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
return originalMethod.call(this, req, res, next);
|
||||
} catch (error) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: '权限不足'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return descriptor;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 动态权限检查中间件
|
||||
* 根据请求参数动态确定所需权限
|
||||
* @param {Function} permissionResolver - 权限解析函数
|
||||
* @returns {Function} Express中间件函数
|
||||
*/
|
||||
const requireDynamicPermission = (permissionResolver) => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
const requiredPermissions = await permissionResolver(req);
|
||||
const middleware = requirePermission(requiredPermissions);
|
||||
return middleware(req, res, next);
|
||||
} catch (error) {
|
||||
console.error('动态权限检查失败:', error);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '权限检查失败'
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
requirePermission,
|
||||
requireSinglePermission,
|
||||
requireAnyPermission,
|
||||
requireAllPermissions,
|
||||
requireAdmin,
|
||||
requireSuperAdmin,
|
||||
withPermission,
|
||||
requireDynamicPermission
|
||||
};
|
||||
254
insurance_backend/src/services/permissionService.js
Normal file
254
insurance_backend/src/services/permissionService.js
Normal file
@@ -0,0 +1,254 @@
|
||||
const { User, Role, Permission, RolePermission } = require('../models');
|
||||
|
||||
/**
|
||||
* 权限服务类 - 提供动态权限检查和管理功能
|
||||
*/
|
||||
class PermissionService {
|
||||
/**
|
||||
* 检查用户是否具有指定权限
|
||||
* @param {number} userId - 用户ID
|
||||
* @param {string} permissionCode - 权限代码
|
||||
* @returns {Promise<boolean>} 是否具有权限
|
||||
*/
|
||||
static async checkUserPermission(userId, permissionCode) {
|
||||
try {
|
||||
const user = await User.findByPk(userId, {
|
||||
include: [{
|
||||
model: Role,
|
||||
as: 'role',
|
||||
include: [{
|
||||
model: Permission,
|
||||
as: 'permissions',
|
||||
where: { code: permissionCode },
|
||||
required: false
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
if (!user || !user.role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.role.permissions && user.role.permissions.length > 0;
|
||||
} catch (error) {
|
||||
console.error('检查用户权限失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否具有多个权限中的任意一个
|
||||
* @param {number} userId - 用户ID
|
||||
* @param {string[]} permissionCodes - 权限代码数组
|
||||
* @returns {Promise<boolean>} 是否具有任意一个权限
|
||||
*/
|
||||
static async checkUserAnyPermission(userId, permissionCodes) {
|
||||
try {
|
||||
const user = await User.findByPk(userId, {
|
||||
include: [{
|
||||
model: Role,
|
||||
as: 'role',
|
||||
include: [{
|
||||
model: Permission,
|
||||
as: 'permissions',
|
||||
where: { code: permissionCodes },
|
||||
required: false
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
if (!user || !user.role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.role.permissions && user.role.permissions.length > 0;
|
||||
} catch (error) {
|
||||
console.error('检查用户权限失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否具有所有指定权限
|
||||
* @param {number} userId - 用户ID
|
||||
* @param {string[]} permissionCodes - 权限代码数组
|
||||
* @returns {Promise<boolean>} 是否具有所有权限
|
||||
*/
|
||||
static async checkUserAllPermissions(userId, permissionCodes) {
|
||||
try {
|
||||
const user = await User.findByPk(userId, {
|
||||
include: [{
|
||||
model: Role,
|
||||
as: 'role',
|
||||
include: [{
|
||||
model: Permission,
|
||||
as: 'permissions',
|
||||
where: { code: permissionCodes },
|
||||
required: false
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
if (!user || !user.role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const userPermissions = user.role.permissions || [];
|
||||
return permissionCodes.every(code =>
|
||||
userPermissions.some(permission => permission.code === code)
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('检查用户权限失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的所有权限
|
||||
* @param {number} userId - 用户ID
|
||||
* @returns {Promise<string[]>} 用户权限代码数组
|
||||
*/
|
||||
static async getUserPermissions(userId) {
|
||||
try {
|
||||
const user = await User.findByPk(userId, {
|
||||
include: [{
|
||||
model: Role,
|
||||
as: 'role',
|
||||
include: [{
|
||||
model: Permission,
|
||||
as: 'permissions'
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
if (!user || !user.role || !user.role.permissions) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return user.role.permissions.map(permission => permission.code);
|
||||
} catch (error) {
|
||||
console.error('获取用户权限失败:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色的所有权限
|
||||
* @param {number} roleId - 角色ID
|
||||
* @returns {Promise<Permission[]>} 权限对象数组
|
||||
*/
|
||||
static async getRolePermissions(roleId) {
|
||||
try {
|
||||
const role = await Role.findByPk(roleId, {
|
||||
include: [{
|
||||
model: Permission,
|
||||
as: 'permissions'
|
||||
}]
|
||||
});
|
||||
|
||||
return role ? role.permissions || [] : [];
|
||||
} catch (error) {
|
||||
console.error('获取角色权限失败:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查权限是否存在
|
||||
* @param {string} permissionCode - 权限代码
|
||||
* @returns {Promise<boolean>} 权限是否存在
|
||||
*/
|
||||
static async permissionExists(permissionCode) {
|
||||
try {
|
||||
const permission = await Permission.findOne({
|
||||
where: { code: permissionCode }
|
||||
});
|
||||
return !!permission;
|
||||
} catch (error) {
|
||||
console.error('检查权限存在性失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限树结构
|
||||
* @returns {Promise<Object[]>} 权限树
|
||||
*/
|
||||
static async getPermissionTree() {
|
||||
try {
|
||||
const permissions = await Permission.findAll({
|
||||
order: [['module', 'ASC'], ['type', 'ASC'], ['code', 'ASC']]
|
||||
});
|
||||
|
||||
// 按模块分组
|
||||
const modules = {};
|
||||
permissions.forEach(permission => {
|
||||
if (!modules[permission.module]) {
|
||||
modules[permission.module] = {
|
||||
module: permission.module,
|
||||
permissions: []
|
||||
};
|
||||
}
|
||||
modules[permission.module].permissions.push(permission);
|
||||
});
|
||||
|
||||
return Object.values(modules);
|
||||
} catch (error) {
|
||||
console.error('获取权限树失败:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量检查用户权限
|
||||
* @param {number} userId - 用户ID
|
||||
* @param {string[]} permissionCodes - 权限代码数组
|
||||
* @returns {Promise<Object>} 权限检查结果对象
|
||||
*/
|
||||
static async batchCheckUserPermissions(userId, permissionCodes) {
|
||||
try {
|
||||
const userPermissions = await this.getUserPermissions(userId);
|
||||
const result = {};
|
||||
|
||||
permissionCodes.forEach(code => {
|
||||
result[code] = userPermissions.includes(code);
|
||||
});
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('批量检查用户权限失败:', error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户可访问的菜单
|
||||
* @param {number} userId - 用户ID
|
||||
* @returns {Promise<Object[]>} 可访问的菜单数组
|
||||
*/
|
||||
static async getUserAccessibleMenus(userId) {
|
||||
try {
|
||||
const userPermissions = await this.getUserPermissions(userId);
|
||||
|
||||
// 这里可以根据权限过滤菜单
|
||||
// 示例:假设菜单与权限有对应关系
|
||||
const allMenus = [
|
||||
{ id: 1, name: '用户管理', permission: 'user:view', path: '/users' },
|
||||
{ id: 2, name: '角色管理', permission: 'role:view', path: '/roles' },
|
||||
{ id: 3, name: '权限管理', permission: 'permission:view', path: '/permissions' },
|
||||
{ id: 4, name: '保单管理', permission: 'policy:view', path: '/policies' },
|
||||
{ id: 5, name: '理赔管理', permission: 'claim:view', path: '/claims' },
|
||||
{ id: 6, name: '系统设置', permission: 'system:view', path: '/system' }
|
||||
];
|
||||
|
||||
return allMenus.filter(menu =>
|
||||
userPermissions.includes(menu.permission)
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('获取用户可访问菜单失败:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PermissionService;
|
||||
Reference in New Issue
Block a user