在 NestJS 中,是否可以根据用户的角色或访问级别有条件地修改控制器方法中请求正文的属性?
例如,如果用户缺乏必要的权限,则应从请求正文中省略他们无权更改的特定属性。
目前,我使用
class-validator
和 class-transformer
使用数据传输对象 (DTO) 进行主体验证,但我不确定如何访问请求对象来执行此类条件逻辑。
详细来说,访问请求对象对于验证正文至关重要,因为它可能包含用户组或角色等关键信息。
以下是我的用户模型供参考:
enum Role {
USER,
ADMIN
}
model User {
id String @id @default(uuid()) @db.Uuid
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
mobileNumber String @unique
role Role @default(USER)
otpCode String?
otpExpiredAt DateTime?
firstName String?
lastName String?
}
这是我的 DTO:
export class UpdateUserDto implements Partial<User> {
@IsOptional()
@IsString()
firstName?: string;
@IsOptional()
@IsString()
lastName?: string;
@IsOptional()
@IsMobilePhone()
mobileNumber?: string;
@IsOptional()
@IsEnum($Enums.Role)
role?: $Enums.Role;
}
要求只有具有“管理员角色”的用户才有权更新 role
属性。如果
非管理员用户尝试发送
role
属性,则应将其从请求正文中排除。此外,虽然我在 request
中有用户信息,但我需要在
DTO
中访问此信息的指导,类似于如何使用组属性。我考虑使用 applyDecorators
来实现此目的,但我无法找到在其范围内访问请求的方法。
export const SerializerDtoByRule = ({ groups }: {groups: $Enums.Role[] }) => {
return applyDecorators(
Expose(({ value }) => {
if (groups.length === 0) return value;
const user = request; // ?? how to accsess request
if (user && groups.includes(user.role)) {
return value;
}
return undefinded;
}),
);
};
@Injectable()
export class UserService {
constructor(
@Inject(REQUEST) private request: Record<string, unknown>,
private readonly userRepository: RepositoryForUser,
) {}
async updateUser(dto: UpdateUserDto) {
let updatable = await this.userRepository.findOneOrThrow(dto.id);
if (!!dto.someImportantField && dto.someImportantField !== updatable.someImportantField) {
this.allowOnly(Role.Admin);
updatable.someImportantField = dto.someImportantField;
}
}
private allowOnly(...roles: Role[]) {
// check from request if matches any role, if not:
throw new UnauthorizedException();
}
}
Dto 层或多或少是一个数据传输对象层。最好放置基本的验证逻辑,例如国家/地区代码是否真的是国家/地区代码,或者检查是否提供了所有需要提供的数据,因为这很容易做到。但是没有必要费力,特别是当目标是放置一些“较重”的业务逻辑时,即服务、域服务、cqrs 处理程序等。 另一个论点是,重载 DTO 并不总是最好,这是一个简单的例子:
user can't update e-mail address
unless they are admins
or they are updating their own e-mail
but only if they hadn't updated their e-mails for at least one month before
您可以将其写在 dtos 中,但随后有人会出现并告诉您:“嘿,我想知道谁是可疑的,我希望将每次电子邮件更改尝试的日志存储在应用程序中”。
谈到通过类验证器访问
Request
- 请参阅
https://github.com/typestack/class-validator?tab=readme-ov-file#custom-validation-classes。您始终可以创建一个类。如果你能做到这一点,你也可以将其制成可注射的。然后 - 你知道:)