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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user