收口 Phase 0 三处「声明未生效」: - 三级鉴权落地:权限集存 Redis(key 前缀隔离多项目),@RequirePermissions 挂到全部受控接口,super_admin 角色绕过权限码与 data_scope - 审计/登录日志自动落库:@AuditLog 装饰器 + 拦截器异步写入(写操作+登录登出),登录成功/失败均记 login_log(脱敏) - seed 脚本:一键初始化租户 touyun/用户 touyun/超管 super_admin/全量资源树(48 资源全量授权) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
47 lines
1.6 KiB
TypeScript
47 lines
1.6 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { BaseCrudService } from '../common/base-crud.service.js';
|
|
import { PrismaService } from '../prisma/prisma.service.js';
|
|
import { RedisService } from '../common/redis/redis.service.js';
|
|
import { getRequestContext } from '../common/context/request-context.js';
|
|
import { AssignResourcesDto, CreateRoleDto, UpdateRoleDto } from './dto.js';
|
|
|
|
@Injectable()
|
|
export class RolesService extends BaseCrudService {
|
|
constructor(
|
|
prisma: PrismaService,
|
|
private readonly redis: RedisService,
|
|
) {
|
|
super(prisma, 'role');
|
|
}
|
|
|
|
createRole(dto: CreateRoleDto) {
|
|
return this.create({ ...dto });
|
|
}
|
|
|
|
updateRole(id: string, dto: UpdateRoleDto) {
|
|
return this.update(id, { ...dto });
|
|
}
|
|
|
|
async assignedResources(roleCode: string) {
|
|
const ctx = getRequestContext()!;
|
|
const rows = await this.prisma.client.roleResource.findMany({
|
|
where: { tenantCode: ctx.tenantCode, roleCode },
|
|
select: { resourceCode: true },
|
|
});
|
|
return rows.map((r) => r.resourceCode);
|
|
}
|
|
|
|
async assignResources(roleCode: string, dto: AssignResourcesDto) {
|
|
const ctx = getRequestContext()!;
|
|
await this.prisma.client.roleResource.deleteMany({ where: { tenantCode: ctx.tenantCode, roleCode } });
|
|
if (dto.resourceCodes.length > 0) {
|
|
await this.prisma.client.roleResource.createMany({
|
|
data: dto.resourceCodes.map((resourceCode) => ({ tenantCode: ctx.tenantCode, roleCode, resourceCode })),
|
|
});
|
|
}
|
|
// 授权变更:删除该租户全部用户权限缓存,下一次请求守卫重新聚合并回填
|
|
await this.redis.delByPrefix(`perm:${ctx.tenantCode}:`);
|
|
return null;
|
|
}
|
|
}
|