Files
IdP/apps/api-gateway/src/controllers/rbac.controller.ts
2026-06-24 14:37:15 +03:00

104 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Body, Controller, Delete, Get, Param, Patch, Post, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger';
import { map } from 'rxjs';
import { CoreGrpcService } from '../core-grpc.service';
import { CurrentAdmin } from '../decorators/current-admin.decorator';
import { AssignUserRoleDto, CreateOAuthClientDto, CreateRoleDto, UpdateOAuthClientDto } from '../dto/rbac.dto';
import { AdminGuard, AdminRequestUser, assertAdminPermission, SuperAdminGuard } from '../guards/admin.guard';
@ApiTags('RBAC и OAuth')
@ApiBearerAuth()
@UseGuards(AdminGuard)
@Controller('admin/rbac')
export class RbacController {
constructor(private readonly core: CoreGrpcService) {}
@Get('roles')
@ApiOperation({ summary: 'Список ролей', description: 'Возвращает роли вместе с назначенными правами.' })
listRoles() {
return this.core.rbac.ListRoles({}).pipe(
map((response) => {
const payload = response as { roles?: Array<{ permissions?: unknown[] }> };
return {
roles: (payload.roles ?? []).map((role) => ({
...role,
permissions: role.permissions ?? []
}))
};
})
);
}
@Get('permissions')
@UseGuards(SuperAdminGuard)
@ApiOperation({ summary: 'Список прав', description: 'Возвращает все доступные permissions.' })
listPermissions() {
return this.core.rbac.ListPermissions({});
}
@Get('oauth-scopes')
@ApiOperation({ summary: 'OAuth scopes', description: 'Возвращает доступные scopes для OAuth-приложений.' })
listOAuthScopes(@CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageOAuth');
return this.core.rbac.ListOAuthScopes({});
}
@Get('oauth-clients')
@ApiOperation({ summary: 'OAuth приложения', description: 'Возвращает OAuth-клиенты и доступные scopes.' })
listOAuthClients(@CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageOAuth');
return this.core.rbac.ListOAuthClients({});
}
@Post('roles')
@UseGuards(SuperAdminGuard)
@ApiOperation({ summary: 'Создать роль', description: 'Создаёт новую роль с набором прав. Только супер-администратор.' })
@ApiBody({ type: CreateRoleDto })
createRole(@Body() dto: CreateRoleDto, @CurrentAdmin() admin: AdminRequestUser) {
return this.core.rbac.CreateRole({ actorUserId: admin.id, ...dto });
}
@Post('users/:userId/roles')
@UseGuards(SuperAdminGuard)
@ApiOperation({ summary: 'Назначить роль пользователю', description: 'Только супер-администратор может назначать роли.' })
@ApiParam({ name: 'userId', description: 'ID пользователя' })
@ApiBody({ type: AssignUserRoleDto })
assignRole(@Param('userId') userId: string, @Body() dto: AssignUserRoleDto, @CurrentAdmin() admin: AdminRequestUser) {
return this.core.rbac.AssignUserRole({ actorUserId: admin.id, userId, roleSlug: dto.roleSlug });
}
@Delete('users/:userId/roles/:roleSlug')
@UseGuards(SuperAdminGuard)
@ApiOperation({ summary: 'Снять роль с пользователя', description: 'Только супер-администратор может снимать роли.' })
@ApiParam({ name: 'userId', description: 'ID пользователя' })
@ApiParam({ name: 'roleSlug', description: 'Slug роли' })
removeRole(@Param('userId') userId: string, @Param('roleSlug') roleSlug: string, @CurrentAdmin() admin: AdminRequestUser) {
return this.core.rbac.RemoveUserRole({ actorUserId: admin.id, userId, roleSlug });
}
@Post('oauth-clients')
@ApiOperation({ summary: 'Создать OAuth-приложение', description: 'Создаёт OAuth2-клиент и возвращает client secret один раз.' })
@ApiBody({ type: CreateOAuthClientDto })
createOAuthClient(@Body() dto: CreateOAuthClientDto, @CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageOAuth');
return this.core.rbac.CreateOAuthClient({ actorUserId: admin.id, ...dto });
}
@Patch('oauth-clients/:clientId')
@ApiOperation({ summary: 'Обновить OAuth-приложение', description: 'Изменяет redirect URI, scopes и статус приложения.' })
@ApiParam({ name: 'clientId', description: 'Client ID приложения' })
@ApiBody({ type: UpdateOAuthClientDto })
updateOAuthClient(@Param('clientId') clientId: string, @Body() dto: UpdateOAuthClientDto, @CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageOAuth');
return this.core.rbac.UpdateOAuthClient({ actorUserId: admin.id, clientId, ...dto });
}
@Post('oauth-clients/:clientId/rotate-secret')
@ApiOperation({ summary: 'Перевыпустить client secret', description: 'Генерирует новый secret для confidential-клиента.' })
@ApiParam({ name: 'clientId', description: 'Client ID приложения' })
rotateSecret(@Param('clientId') clientId: string, @CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageOAuth');
return this.core.rbac.RotateOAuthSecret({ actorUserId: admin.id, clientId });
}
}