import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Role } from './role.entity'; import { RolePermission } from './role-permission.entity'; import { ALL_PERMISSIONS, PERMISSION_META, PermissionKey, PermissionMeta } from './permission.constants'; import { UserRole } from '../../user/user-role.enum'; import { TenantMember } from '../../tenant/tenant-member.entity'; import { User } from '../../user/user.entity'; import { ConfigService } from '@nestjs/config'; /** * 角色预设——系统内置角色默认挂载的权限 */ const ROLE_DEFAULT_PERMISSIONS: Record = { [UserRole.SUPER_ADMIN]: [...ALL_PERMISSIONS], [UserRole.TENANT_ADMIN]: [ // 用户管理(不含删除和角色管理——安全考虑) 'user:view', 'user:create', 'user:edit', 'user:password', // 租户管理(只能查看和编辑自己的) 'tenant:view', 'tenant:edit', 'tenant:members', // 知识库 'kb:view', 'kb:create', 'kb:edit', 'kb:delete', 'kb:publish', // 考核评估 'assess:view', 'assess:manage', 'assess:template', 'assess:bank', // 模型配置 'model:view', 'model:config', // 插件 'plugin:view', 'plugin:manage', // 设置 'settings:view', ], [UserRole.USER]: [ 'kb:view', 'kb:create', 'kb:edit', 'assess:view', 'plugin:view', ], }; @Injectable() export class PermissionService implements OnModuleInit { private readonly logger = new Logger(PermissionService.name); constructor( @InjectRepository(Role) private readonly roleRepository: Repository, @InjectRepository(RolePermission) private readonly rolePermissionRepository: Repository, @InjectRepository(TenantMember) private readonly tenantMemberRepository: Repository, @InjectRepository(User) private readonly userRepository: Repository, private readonly configService: ConfigService, ) {} /** * 启动时自动种子化系统角色和权限 */ async onModuleInit() { const isTest = this.configService.get('NODE_ENV') === 'test'; if (isTest) return; try { const existing = await this.roleRepository.count({ where: { isSystem: true } }); if (existing > 0) { this.logger.log(`[Permission Seed] ${existing} 个系统角色已存在,跳过`); return; } await this.seedSystemRoles(); this.logger.log('[Permission Seed] ✅ 系统角色和权限已初始化'); } catch (err) { this.logger.error('[Permission Seed] ❌ 初始化失败:', err); } } private async seedSystemRoles() { const roles = [ { name: UserRole.SUPER_ADMIN, baseRole: UserRole.SUPER_ADMIN }, { name: UserRole.TENANT_ADMIN, baseRole: UserRole.TENANT_ADMIN }, { name: UserRole.USER, baseRole: UserRole.USER }, ]; for (const r of roles) { const role = await this.roleRepository.save({ name: r.name, description: this.getRoleDescription(r.name as UserRole), isSystem: true, baseRole: r.baseRole, tenantId: null, }); const perms = ROLE_DEFAULT_PERMISSIONS[r.name] || []; if (perms.length > 0) { await this.rolePermissionRepository.save( perms.map(key => ({ roleId: role.id, permissionKey: key })), ); } this.logger.log(` - ${r.name}: ${perms.length} 项权限`); } } private getRoleDescription(role: UserRole): string { switch (role) { case UserRole.SUPER_ADMIN: return '全局超级管理员——拥有系统全部权限'; case UserRole.TENANT_ADMIN: return '租户管理员——管理本租户内的用户和资源'; case UserRole.USER: return '普通用户——使用系统功能'; } } // ──────────── 角色 CRUD ──────────── async findAllRoles(tenantId?: string): Promise { const where: any[] = [{ isSystem: true, tenantId: null }]; if (tenantId) { where.push({ tenantId, isSystem: false }); } return this.roleRepository.find({ where, order: { isSystem: 'DESC', name: 'ASC' } }); } async findRoleById(id: string): Promise { return this.roleRepository.findOne({ where: { id } }); } async createRole(name: string, description: string, tenantId: string): Promise { const existing = await this.roleRepository.findOne({ where: { name } }); if (existing) throw new Error(`角色名 "${name}" 已存在`); return this.roleRepository.save({ name, description, isSystem: false, baseRole: null, tenantId, }); } async updateRole(id: string, data: { name?: string; description?: string }): Promise { const role = await this.roleRepository.findOne({ where: { id } }); if (!role) throw new Error('角色不存在'); if (role.isSystem) throw new Error('系统角色不可编辑'); if (data.name) role.name = data.name; if (data.description !== undefined) role.description = data.description; return this.roleRepository.save(role); } async deleteRole(id: string): Promise { const role = await this.roleRepository.findOne({ where: { id } }); if (!role) throw new Error('角色不存在'); if (role.isSystem) throw new Error('系统角色不可删除'); await this.roleRepository.remove(role); } // ──────────── 权限管理 ──────────── async getRolePermissions(roleId: string): Promise { const rps = await this.rolePermissionRepository.find({ where: { roleId }, }); return rps.map(rp => rp.permissionKey); } async setRolePermissions(roleId: string, permissionKeys: string[]): Promise { const role = await this.roleRepository.findOne({ where: { id: roleId } }); if (!role) throw new Error('角色不存在'); if (role.isSystem) throw new Error('系统角色的权限不可修改'); // 验证权限键是否有效 const valid = ALL_PERMISSIONS; const invalid = permissionKeys.filter(k => !valid.includes(k as any)); if (invalid.length > 0) throw new Error(`无效的权限: ${invalid.join(', ')}`); // 替换角色的所有权限 await this.rolePermissionRepository.delete({ roleId }); if (permissionKeys.length > 0) { await this.rolePermissionRepository.save( permissionKeys.map(key => ({ roleId, permissionKey: key })), ); } } // ──────────── 用户权限解析 ──────────── /** * 获取用户在指定租户下的最终权限集 * * 解析链路: * 1. 如果是 global admin(isAdmin=true),直接返回所有权限 * 2. 通过 TenantMember.role → 对应 role → role_permissions */ async getUserPermissions(userId: string, tenantId: string): Promise> { // 检查全局管理员(遗留 isAdmin 字段) const user = await this.userRepository.findOne({ where: { id: userId }, select: ['id', 'isAdmin'], }); if (user?.isAdmin) { const superAdminRole = await this.roleRepository.findOne({ where: { baseRole: UserRole.SUPER_ADMIN, isSystem: true }, }); if (superAdminRole) { const perms = await this.getRolePermissions(superAdminRole.id); return new Set(perms); } } // 通过租户成员角色 const membership = await this.tenantMemberRepository.findOne({ where: { userId, tenantId }, }); if (!membership) return new Set(); const role = await this.roleRepository.findOne({ where: { baseRole: membership.role, isSystem: true }, }); if (!role) return new Set(); const perms = await this.getRolePermissions(role.id); return new Set(perms); } /** * 检查用户是否有指定权限 */ async checkPermission(userId: string, tenantId: string, permissionKey: string): Promise { // 先尝试从请求级缓存获取(由 PermissionsGuard 设置) const perms = await this.getUserPermissions(userId, tenantId); return perms.has(permissionKey); } // ──────────── 元数据 ──────────── getAllPermissionMeta(): PermissionMeta[] { return PERMISSION_META; } getPermissionsByCategory(): Record { const grouped: Record = {}; for (const meta of PERMISSION_META) { if (!grouped[meta.category]) grouped[meta.category] = []; grouped[meta.category].push(meta); } return grouped; } }