import { Middleware, IMiddleware } from "@midwayjs/core"; import { Context, NextFunction } from "@midwayjs/koa"; import { Provide, Inject } from "@midwayjs/core"; import { InjectRepository } from "@midwayjs/sequelize"; import { PermissionService } from "../service/permission.service"; import SysUserRole from "../entity/sysUserRole.entity"; import SysRole from "../entity/sysRole.entity"; // 请求路径前缀 → 菜单权限标识映射 const PERMISSION_MAP: Record = { "/api/users": "system:user", "/api/roles": "system:role", "/api/menus": "system:menu", "/api/dicts": "system:dict", "/api/logs": "system:log", "/api/jobs": "system:job", "/api/notice-rules": "notice:rule", "/api/notice-batches": "notice:batch", "/api/customers": "customer:list", "/api/customer-departments": "customer:department", "/api/customer-accounts": "customer:account", "/api/customer-visits": "customer:visit", "/api/upload": "customer:visit", "/api/customer-buildings": "customer:building", "/api/customer-rooms": "customer:room", "/api/survey-orders": "project:survey", "/api/project-plans": "project:plan", "/api/contracts": "project:contract", "/api/install-orders": "project:install", "/api/acceptances": "project:acceptance", "/api/visit-records": "project:visit", "/api/repair-requests": "dispatch:repair", "/api/repair-dispatchs": "dispatch:repair", "/api/maintenance-orders": "dispatch:maintenance", "/api/service-prices": "dispatch:price", "/api/dispatch-prices": "dispatch:cost", "/api/workers": "dispatch:worker" }; // 超级管理员角色编码,拥有全部权限 const ADMIN_ROLE_CODE = "ADMIN"; @Provide() export class RbacMiddleware implements IMiddleware { // 中间件匹配范围:全局生效,跳过公开接口、仪表盘与电工 APP 接口 // /api/workers/options 与 /api/workers/recommend 放行:业务员在「项目勘察派单」页 // 仍可调用电工下拉与推荐接口,不受 dispatch:worker 权限限制(本次需求有意设计) ignore = ["/api/auth/*", "/api/health", "/api/dashboard/*", "/api/worker-app/*", "/api/workers/options", "/api/workers/recommend"]; @Inject() permissionService!: PermissionService; @InjectRepository(SysUserRole) userRoleModel!: typeof SysUserRole; @InjectRepository(SysRole) roleModel!: typeof SysRole; resolve() { return async (ctx: Context, next: NextFunction) => { const user = ctx.state.user; if (!user) { ctx.status = 401; ctx.body = { code: 401, message: "未登录" }; return; } // 路径前缀匹配,未匹配到任何权限映射的请求直接放行 const permissionCode = this.matchPermissionCode(ctx.path); if (!permissionCode) { await next(); return; } // 查询用户角色编码,超级管理员直接放行 const roleCodes = await this.getUserRoleCodes(user.userId); if (roleCodes.includes(ADMIN_ROLE_CODE)) { await next(); return; } // 检查用户菜单中是否包含该权限标识 const hasPermission = await this.permissionService.checkUserPermission(user.userId, permissionCode); if (!hasPermission) { ctx.status = 403; ctx.body = { code: 403, message: "没有访问权限" }; return; } await next(); }; } private matchPermissionCode(path: string): string { for (const [prefix, code] of Object.entries(PERMISSION_MAP)) { if (path === prefix || path.startsWith(prefix + "/")) { return code; } } return ""; } private async getUserRoleCodes(userId: number): Promise { const userRoles = await this.userRoleModel.findAll({ where: { userId }, include: [this.roleModel] }); return userRoles.map((ur) => ur.role?.roleCode).filter(Boolean) as string[]; } }