feat: 分层 RBAC 权限管理系统

后端:
- 新增 Role / RolePermission 实体(自动 seed 系统角色)
- PermissionService——通过 isAdmin / TenantMember 链路解析用户权限
- @Permission() 装饰器 + PermissionsGuard 守卫
- /api/permissions 和 /api/roles REST API
- UserController 内联 role 检查迁移到 @Permission()
- PermissionModule 全局注册

前端:
- usePermissions hook——获取当前用户权限集
- PermissionGate 组件级门控
- PermissionSettingsView——角色列表+权限矩阵编辑页面
- SettingsView 新增「权限管理」Tab(仅 admin 可见)
- 权限预览(26 项,7 分类)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Developer
2026-06-08 23:25:22 +08:00
parent c57c3028e2
commit ba33d517c1
17 changed files with 1386 additions and 87 deletions
+2
View File
@@ -36,6 +36,7 @@ import { TenantModule } from './tenant/tenant.module';
import { SuperAdminModule } from './super-admin/super-admin.module';
import { AdminModule } from './admin/admin.module';
import { FeishuModule } from './feishu/feishu.module';
import { PermissionModule } from './auth/permission/permission.module';
@Module({
imports: [
@@ -82,6 +83,7 @@ import { FeishuModule } from './feishu/feishu.module';
SuperAdminModule,
AdminModule,
FeishuModule,
PermissionModule,
],
controllers: [AppController],
providers: [
@@ -0,0 +1,108 @@
/**
* 所有可用权限的常量定义
* 格式: resource:action
*
* 分类说明:
* - user: 用户管理
* - tenant: 租户管理
* - kb: 知识库
* - assess: 考核评估
* - model: 模型配置
* - plugin: 插件管理
* - settings: 系统设置
*/
export const PERMISSIONS = {
// ── 用户管理 ──
USER_VIEW: 'user:view',
USER_CREATE: 'user:create',
USER_EDIT: 'user:edit',
USER_DELETE: 'user:delete',
USER_ROLE: 'user:role', // 修改他人角色/权限
USER_PASSWORD: 'user:password', // 重置他人密码
// ── 租户管理 ──
TENANT_VIEW: 'tenant:view',
TENANT_CREATE: 'tenant:create',
TENANT_EDIT: 'tenant:edit',
TENANT_DELETE: 'tenant:delete',
TENANT_MEMBERS: 'tenant:members',
// ── 知识库 ──
KB_VIEW: 'kb:view',
KB_CREATE: 'kb:create',
KB_EDIT: 'kb:edit',
KB_DELETE: 'kb:delete',
KB_PUBLISH: 'kb:publish',
// ── 考核评估 ──
ASSESS_VIEW: 'assess:view',
ASSESS_MANAGE: 'assess:manage',
ASSESS_TEMPLATE: 'assess:template',
ASSESS_BANK: 'assess:bank',
// ── 模型配置 ──
MODEL_VIEW: 'model:view',
MODEL_CONFIG: 'model:config',
// ── 插件管理 ──
PLUGIN_VIEW: 'plugin:view',
PLUGIN_MANAGE: 'plugin:manage',
// ── 系统设置 ──
SETTINGS_VIEW: 'settings:view',
SETTINGS_SYSTEM: 'settings:system',
} as const;
export type PermissionKey = (typeof PERMISSIONS)[keyof typeof PERMISSIONS];
export const ALL_PERMISSIONS = Object.values(PERMISSIONS) as PermissionKey[];
/** 权限分类元数据——给前端渲染用 */
export interface PermissionMeta {
key: PermissionKey;
category: string;
label: string;
description: string;
}
export const PERMISSION_META: PermissionMeta[] = [
// ── 用户管理 ──
{ key: PERMISSIONS.USER_VIEW, category: '用户管理', label: '查看用户', description: '查看用户列表和基本信息' },
{ key: PERMISSIONS.USER_CREATE, category: '用户管理', label: '创建用户', description: '添加新用户到系统' },
{ key: PERMISSIONS.USER_EDIT, category: '用户管理', label: '编辑用户', description: '修改用户基本信息' },
{ key: PERMISSIONS.USER_DELETE, category: '用户管理', label: '删除用户', description: '从系统删除用户' },
{ key: PERMISSIONS.USER_ROLE, category: '用户管理', label: '管理角色', description: '修改用户角色和权限' },
{ key: PERMISSIONS.USER_PASSWORD, category: '用户管理', label: '重置密码', description: '重置其他用户的密码' },
// ── 租户管理 ──
{ key: PERMISSIONS.TENANT_VIEW, category: '租户管理', label: '查看租户', description: '查看租户信息和成员' },
{ key: PERMISSIONS.TENANT_CREATE, category: '租户管理', label: '创建租户', description: '创建新的租户' },
{ key: PERMISSIONS.TENANT_EDIT, category: '租户管理', label: '编辑租户', description: '修改租户设置' },
{ key: PERMISSIONS.TENANT_DELETE, category: '租户管理', label: '删除租户', description: '删除租户' },
{ key: PERMISSIONS.TENANT_MEMBERS, category: '租户管理', label: '管理成员', description: '添加/移除租户成员' },
// ── 知识库 ──
{ key: PERMISSIONS.KB_VIEW, category: '知识库', label: '查看知识库', description: '查看知识库内容' },
{ key: PERMISSIONS.KB_CREATE, category: '知识库', label: '创建知识库', description: '创建新的知识库' },
{ key: PERMISSIONS.KB_EDIT, category: '知识库', label: '编辑知识库', description: '编辑知识库内容' },
{ key: PERMISSIONS.KB_DELETE, category: '知识库', label: '删除知识库', description: '删除知识库' },
{ key: PERMISSIONS.KB_PUBLISH, category: '知识库', label: '发布知识库', description: '将知识库发布上线' },
// ── 考核评估 ──
{ key: PERMISSIONS.ASSESS_VIEW, category: '考核评估', label: '查看考核', description: '查看考核结果和报告' },
{ key: PERMISSIONS.ASSESS_MANAGE, category: '考核评估', label: '管理考核', description: '管理考核会话' },
{ key: PERMISSIONS.ASSESS_TEMPLATE, category: '考核评估', label: '管理模板', description: '创建和编辑考核模板' },
{ key: PERMISSIONS.ASSESS_BANK, category: '考核评估', label: '管理题库', description: '管理题库内容' },
// ── 模型配置 ──
{ key: PERMISSIONS.MODEL_VIEW, category: '模型配置', label: '查看模型', description: '查看模型配置' },
{ key: PERMISSIONS.MODEL_CONFIG, category: '模型配置', label: '配置模型', description: '修改模型配置' },
// ── 插件管理 ──
{ key: PERMISSIONS.PLUGIN_VIEW, category: '插件管理', label: '查看插件', description: '查看插件列表' },
{ key: PERMISSIONS.PLUGIN_MANAGE, category: '插件管理', label: '管理插件', description: '启停和配置插件' },
// ── 系统设置 ──
{ key: PERMISSIONS.SETTINGS_VIEW, category: '系统设置', label: '查看设置', description: '查看系统设置' },
{ key: PERMISSIONS.SETTINGS_SYSTEM, category: '系统设置', label: '系统设置', description: '修改系统级设置(仅超级管理员)' },
];
@@ -0,0 +1,30 @@
import { Controller, Get, Request, UseGuards } from '@nestjs/common';
import { PermissionService } from './permission.service';
import { CombinedAuthGuard } from '../combined-auth.guard';
@Controller('permissions')
@UseGuards(CombinedAuthGuard)
export class PermissionController {
constructor(private readonly permissionService: PermissionService) {}
/** 获取所有可用权限(含分类) */
@Get()
getAll() {
return this.permissionService.getPermissionsByCategory();
}
/** 获取所有权限的扁平元数据列表 */
@Get('meta')
getMeta() {
return this.permissionService.getAllPermissionMeta();
}
/** 获取当前用户在活动租户下的权限集 */
@Get('mine')
async getMine(@Request() req) {
const userId = req.user.id;
const tenantId = req.tenantId || req.user.tenantId;
const perms = await this.permissionService.getUserPermissions(userId, tenantId);
return { permissions: [...perms] };
}
}
@@ -0,0 +1,16 @@
import { SetMetadata } from '@nestjs/common';
export const PERMISSIONS_KEY = 'permissions';
/**
* 权限装饰器——标记路由需要的权限
* 多个权限之间为 OR 关系(有任一匹配即可)
*
* @example
* ```typescript
* @Permission('user:view') // 需要 user:view 权限
* @Permission('user:create', 'user:edit') // 需要 user:create 或 user:edit
* ```
*/
export const Permission = (...permissions: string[]) =>
SetMetadata(PERMISSIONS_KEY, permissions);
@@ -0,0 +1,49 @@
import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { PermissionService } from './permission.service';
import { PERMISSIONS_KEY } from './permission.decorator';
/**
* 权限守卫——配合 @Permission() 装饰器使用
*
* 在 CombinedAuthGuard 和 RolesGuard 之后运行
* 检查 request.user 是否有 @Permission() 指定的任一权限
*/
@Injectable()
export class PermissionsGuard implements CanActivate {
constructor(
private readonly reflector: Reflector,
private readonly permissionService: PermissionService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const requiredPermissions = this.reflector.getAllAndOverride<string[]>(
PERMISSIONS_KEY,
[context.getHandler(), context.getClass()],
);
if (!requiredPermissions || requiredPermissions.length === 0) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
if (!user) return false;
const userId = user.id;
const tenantId = request.tenantId || user.tenantId;
if (!userId || !tenantId) return false;
const userPermissions = await this.permissionService.getUserPermissions(userId, tenantId);
// OR 模式:任一权限匹配即可
const hasPermission = requiredPermissions.some(p => userPermissions.has(p));
if (!hasPermission) {
throw new ForbiddenException(`需要权限: ${requiredPermissions.join(', ')}`);
}
return true;
}
}
@@ -0,0 +1,20 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Role } from './role.entity';
import { RolePermission } from './role-permission.entity';
import { TenantMember } from '../../tenant/tenant-member.entity';
import { User } from '../../user/user.entity';
import { PermissionService } from './permission.service';
import { PermissionController } from './permission.controller';
import { RoleController } from './role.controller';
import { PermissionsGuard } from './permission.guard';
@Module({
imports: [
TypeOrmModule.forFeature([Role, RolePermission, TenantMember, User]),
],
controllers: [PermissionController, RoleController],
providers: [PermissionService, PermissionsGuard],
exports: [PermissionService, PermissionsGuard],
})
export class PermissionModule {}
@@ -0,0 +1,247 @@
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<string, PermissionKey[]> = {
[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<Role>,
@InjectRepository(RolePermission)
private readonly rolePermissionRepository: Repository<RolePermission>,
@InjectRepository(TenantMember)
private readonly tenantMemberRepository: Repository<TenantMember>,
@InjectRepository(User)
private readonly userRepository: Repository<User>,
private readonly configService: ConfigService,
) {}
/**
* 启动时自动种子化系统角色和权限
*/
async onModuleInit() {
const isTest = this.configService.get<string>('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<Role[]> {
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<Role | null> {
return this.roleRepository.findOne({ where: { id } });
}
async createRole(name: string, description: string, tenantId: string): Promise<Role> {
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<Role> {
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<void> {
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<string[]> {
const rps = await this.rolePermissionRepository.find({
where: { roleId },
});
return rps.map(rp => rp.permissionKey);
}
async setRolePermissions(roleId: string, permissionKeys: string[]): Promise<void> {
const role = await this.roleRepository.findOne({ where: { id: roleId } });
if (!role) 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 adminisAdmin=true),直接返回所有权限
* 2. 通过 TenantMember.role → 对应 role → role_permissions
*/
async getUserPermissions(userId: string, tenantId: string): Promise<Set<string>> {
// 检查全局管理员(遗留 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<boolean> {
// 先尝试从请求级缓存获取(由 PermissionsGuard 设置)
const perms = await this.getUserPermissions(userId, tenantId);
return perms.has(permissionKey);
}
// ──────────── 元数据 ────────────
getAllPermissionMeta(): PermissionMeta[] {
return PERMISSION_META;
}
getPermissionsByCategory(): Record<string, PermissionMeta[]> {
const grouped: Record<string, PermissionMeta[]> = {};
for (const meta of PERMISSION_META) {
if (!grouped[meta.category]) grouped[meta.category] = [];
grouped[meta.category].push(meta);
}
return grouped;
}
}
@@ -0,0 +1,32 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
ManyToOne,
JoinColumn,
} from 'typeorm';
import { Role } from './role.entity';
/**
* 角色-权限关联表
* 每个角色可以挂载多个权限
*/
@Entity('role_permissions')
export class RolePermission {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ name: 'role_id' })
roleId: string;
@ManyToOne(() => Role, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'role_id' })
role: Role;
@Column({ name: 'permission_key', length: 50 })
permissionKey: string;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
}
@@ -0,0 +1,100 @@
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Request,
UseGuards,
NotFoundException,
BadRequestException,
} from '@nestjs/common';
import { PermissionService } from './permission.service';
import { CombinedAuthGuard } from '../combined-auth.guard';
import { RolesGuard } from '../roles.guard';
import { Roles } from '../roles.decorator';
import { UserRole } from '../../user/user-role.enum';
@Controller('roles')
@UseGuards(CombinedAuthGuard, RolesGuard)
export class RoleController {
constructor(private readonly permissionService: PermissionService) {}
/** 列出角色(系统角色 + 租户自定义角色) */
@Get()
@Roles(UserRole.SUPER_ADMIN, UserRole.TENANT_ADMIN)
async findAll(@Request() req) {
const tenantId = req.tenantId || req.user.tenantId;
return this.permissionService.findAllRoles(tenantId);
}
/** 获取单个角色 */
@Get(':id')
@Roles(UserRole.SUPER_ADMIN, UserRole.TENANT_ADMIN)
async findOne(@Param('id') id: string) {
const role = await this.permissionService.findRoleById(id);
if (!role) throw new NotFoundException('角色不存在');
return role;
}
/** 创建自定义角色 */
@Post()
@Roles(UserRole.SUPER_ADMIN, UserRole.TENANT_ADMIN)
async create(@Body() body: { name: string; description?: string }, @Request() req) {
if (!body.name) throw new BadRequestException('角色名不能为空');
const tenantId = req.tenantId || req.user.tenantId;
try {
return await this.permissionService.createRole(body.name, body.description || '', tenantId);
} catch (err: any) {
throw new BadRequestException(err.message);
}
}
/** 修改角色基本信息 */
@Put(':id')
@Roles(UserRole.SUPER_ADMIN, UserRole.TENANT_ADMIN)
async update(@Param('id') id: string, @Body() body: { name?: string; description?: string }) {
try {
return await this.permissionService.updateRole(id, body);
} catch (err: any) {
throw new BadRequestException(err.message);
}
}
/** 删除自定义角色 */
@Delete(':id')
@Roles(UserRole.SUPER_ADMIN, UserRole.TENANT_ADMIN)
async remove(@Param('id') id: string) {
try {
await this.permissionService.deleteRole(id);
return { success: true };
} catch (err: any) {
throw new BadRequestException(err.message);
}
}
/** 获取角色的权限列表 */
@Get(':id/permissions')
@Roles(UserRole.SUPER_ADMIN, UserRole.TENANT_ADMIN)
async getPermissions(@Param('id') id: string) {
const perms = await this.permissionService.getRolePermissions(id);
return { permissions: perms };
}
/** 设置角色的权限(全量替换) */
@Put(':id/permissions')
@Roles(UserRole.SUPER_ADMIN, UserRole.TENANT_ADMIN)
async setPermissions(@Param('id') id: string, @Body() body: { permissions: string[] }) {
if (!Array.isArray(body.permissions)) {
throw new BadRequestException('permissions 必须是数组');
}
try {
await this.permissionService.setRolePermissions(id, body.permissions);
return { success: true, permissions: body.permissions };
} catch (err: any) {
throw new BadRequestException(err.message);
}
}
}
+49
View File
@@ -0,0 +1,49 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
} from 'typeorm';
import { UserRole } from '../../user/user-role.enum';
/**
* 角色表
* is_system = true: 系统内置角色(SUPER_ADMIN/TENANT_ADMIN/USER),不可删除
* tenant_id = null: 系统级角色(所有租户可见)
* tenant_id != null: 租户自定义角色
*/
@Entity('roles')
export class Role {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ unique: true, length: 50 })
name: string;
@Column({ type: 'text', nullable: true })
description: string;
/** 是否为系统内置角色 */
@Column({ name: 'is_system', default: false })
isSystem: boolean;
/** 关联的内置角色 enum(仅 is_system=true 时有值) */
@Column({
name: 'base_role',
type: 'simple-enum',
enum: UserRole,
nullable: true,
})
baseRole: UserRole | null;
/** 所属租户:null=系统级,非 null=租户自定义 */
@Column({ name: 'tenant_id', nullable: true, type: 'text' })
tenantId: string | null;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
}
+12 -46
View File
@@ -20,6 +20,8 @@ import { UpdateUserDto } from './dto/update-user.dto';
import { I18nService } from '../i18n/i18n.service';
import { UserRole } from './user-role.enum';
import { UserSettingService } from './user-setting.service';
import { Permission } from '../auth/permission/permission.decorator';
import { PermissionsGuard } from '../auth/permission/permission.guard';
@Controller('users')
@UseGuards(CombinedAuthGuard)
@@ -92,25 +94,17 @@ export class UserController {
}
@Get()
@UseGuards(PermissionsGuard)
@Permission('user:view')
async findAll(
@Request() req,
@Query('page') page?: string,
@Query('limit') limit?: string,
) {
const callerRole = req.user.role;
if (
callerRole !== UserRole.SUPER_ADMIN &&
callerRole !== UserRole.TENANT_ADMIN
) {
throw new ForbiddenException(
this.i18nService.getErrorMessage('adminOnlyViewList'),
);
}
const p = page ? parseInt(page) : undefined;
const l = limit ? parseInt(limit) : undefined;
if (callerRole === UserRole.SUPER_ADMIN) {
if (req.user.role === UserRole.SUPER_ADMIN) {
return this.userService.findAll(p, l);
} else {
return this.userService.findByTenantId(req.user.tenantId, p, l);
@@ -144,17 +138,9 @@ export class UserController {
}
@Post()
@UseGuards(PermissionsGuard)
@Permission('user:create')
async createUser(@Request() req, @Body() body: CreateUserDto) {
const callerRole = req.user.role;
if (
callerRole !== UserRole.SUPER_ADMIN &&
callerRole !== UserRole.TENANT_ADMIN
) {
throw new ForbiddenException(
this.i18nService.getErrorMessage('adminOnlyCreateUser'),
);
}
const { username, password } = body;
if (!username || !password) {
@@ -169,16 +155,9 @@ export class UserController {
);
}
// All new global users default to non-admin.
// Elevation to Super Admin status is handled separately.
// All new users default to non-admin.
let isAdmin = false;
if (callerRole === UserRole.SUPER_ADMIN) {
isAdmin = false;
} else if (callerRole === UserRole.TENANT_ADMIN) {
isAdmin = false;
}
// Pass the calculated params to the service
return this.userService.createUser(
username,
@@ -190,20 +169,14 @@ export class UserController {
}
@Put(':id')
@UseGuards(PermissionsGuard)
@Permission('user:edit')
async updateUser(
@Request() req,
@Body() body: UpdateUserDto,
@Param('id') id: string,
) {
const callerRole = req.user.role;
if (
callerRole !== UserRole.SUPER_ADMIN &&
callerRole !== UserRole.TENANT_ADMIN
) {
throw new ForbiddenException(
this.i18nService.getErrorMessage('adminOnlyUpdateUser'),
);
}
// Get user info to update
const userToUpdate = await this.userService.findOneById(id);
@@ -228,7 +201,6 @@ export class UserController {
}
// Role modification is now obsolete on global level.
// If Admin wants to elevate, they set isAdmin property directly.
if (body.isAdmin !== undefined && userToUpdate.isAdmin !== body.isAdmin) {
if (callerRole !== UserRole.SUPER_ADMIN) {
throw new ForbiddenException(
@@ -248,16 +220,10 @@ export class UserController {
}
@Delete(':id')
@UseGuards(PermissionsGuard)
@Permission('user:delete')
async deleteUser(@Request() req, @Param('id') id: string) {
const callerRole = req.user.role;
if (
callerRole !== UserRole.SUPER_ADMIN &&
callerRole !== UserRole.TENANT_ADMIN
) {
throw new ForbiddenException(
this.i18nService.getErrorMessage('adminOnlyDeleteUser'),
);
}
// Prevent admin from deleting themselves
if (req.user.id === id) {
+2
View File
@@ -8,12 +8,14 @@ import { ApiKey } from '../auth/entities/api-key.entity';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { TenantModule } from '../tenant/tenant.module';
import { PermissionModule } from '../auth/permission/permission.module';
@Global()
@Module({
imports: [
TypeOrmModule.forFeature([User, ApiKey, TenantMember, UserSetting]),
TenantModule,
PermissionModule,
],
controllers: [UserController],
providers: [UserService, UserSettingService],