使用 DTO 从访问令牌附加用户 ID

Dom*_*nik 5 node.js nestjs

我创建 POST 端点来创建一个新实体。我还使用字段 userId (将此实体连接到指定用户)和 DTO 创建了 mongoose 模式,我在 POST 方法中使用了 DTO。

@UseGuards(JwtAuthGuard)
@Post("/")
createAction(@Request() req, @Body() createActionDto: CreateActionDto) {
    return this.actionService.createAction(req?.user?.userId, createActionDto);
}
Run Code Online (Sandbox Code Playgroud)

数据传输对象:

import { IsString, IsNumber, IsUrl } from 'class-validator';

export class CreateActionDto {
    userId: string;

    @IsString()
    name: string;

    @IsNumber()
    timeStart: number;
}
Run Code Online (Sandbox Code Playgroud)

架构:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

@Schema()
export class Action extends Document {
    @Prop()
    userId: string;

    @Prop()
    name: string;

    @Prop()
    timeStart: number;
}

export const ActionSchema = SchemaFactory.createForClass(Action)
Run Code Online (Sandbox Code Playgroud)

在 req 属性中我有 userId。创建实体并附加从令牌中提取的 userId 的最佳方法是什么?

我是否应该将 req 传递给服务,并在服务中像这样在 DTO 上设置 userId 属性?:

@Injectable()
export class ActionService {
    constructor(
        @InjectModel(Action.name) private actionModel: Model<Action>,
    ) { }

    async createAction(req: string, createActionDto: CreateActionDto) {
        createActionDto.userId = req.user.userId

        // ... save to mongoose createActionDto
    }
}

Run Code Online (Sandbox Code Playgroud)

这是一个正确的解决方案还是有其他更好的方法来处理它?

eol*_*eol 3

就我个人而言,我会在控制器中设置userId,以便不必传递它:

@UseGuards(JwtAuthGuard)
@Post("/")
createAction(@Request() req, @Body() createActionDto: CreateActionDto) {
    createActionDto.userId = req?.user?.userId;
    return this.actionService.createAction(createActionDto);
}
Run Code Online (Sandbox Code Playgroud)

如果您有许多不同的控制器和 DTO 需要,userId您还可以定义一个拦截器并在那里执行它以减少重复:

@Injectable()
export class SetUserIdInterceptor implements NestInterceptor {
  public intercept(_context: ExecutionContext, $next: CallHandler): Observable<any> {    
   const request: any = _context.switchToHttp().getRequest(); //instead of any you could also define a super-class for all DTOs that require the `userId`-property    
   request.body?.userId = req?.user?.userId;
   return $next;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在您的路线上使用此拦截器,如下所示:

@UseGuards(JwtAuthGuard)
@Post("/")
@UseInterceptors(SetUserIdInterceptor)
createAction(@Body() createActionDto: CreateActionDto) {
    return this.actionService.createAction(createActionDto)
}
Run Code Online (Sandbox Code Playgroud)