【问题标题】:Howto get req.user in services in Nest JS如何在 Nestjs 的服务中获取 req.user
【发布时间】:2019-07-25 13:23:46
【问题描述】:

在控制器中,我添加带有保护的用户对象,注入一些服务并调用该服务以获得一些响应。为简洁起见,我删除了很多代码。

@Controller()
@UseGuards(AuthGuard())
export class UserController() {
   constructor(private readonly userService: UsersService) {
   }

   @Get(':id')
   async findOne(@Param('id') id) {
      return await this.userService.findOne(id);
   }
}

由于我有AuthGuard,我现在知道用户在输入:id 路由之前已登录。

在服务中我会做类似的事情

@Injectable()
export class UsersService {
   async findOne(id: number): Promise<User> {
      return await this.usersRepository.findOne({where: {id: id}});
   }
}

当然,我们希望检查登录用户是否有权访问它正在查询的用户。现在的问题是如何获取当前登录的用户。我可以将它作为参数从控制器发送,但由于很多后端需要对当前用户进行安全检查,我不确定这是一个好主意。

@Get(':id')
async findOne(@Param('id') id, @Req() req: any) {
   return await this.userService.findOne(id, req.user);
}

理想情况下,这不起作用,我可以在 UserService 中获取它:

async findOne(id: number, @Req req: any): Promise<User> {
   if (id === req.user.id || req.user.roles.contains('ADMIN')) {
      return await this.userRepository.findOne({where: {id: id}});
   }
}

或者也许通过UserService构造函数中的注入

constructor(@Inject(REQUEST_OBJECT) private readonly req: any) {}

那么,有没有比在每次函数调用中始终发送请求对象更好的方式通过后端发送用户对象?

【问题讨论】:

    标签: javascript node.js typescript nestjs


    【解决方案1】:

    2019 年 3 月更新

    从 v6 版本开始,您现在可以将 request 对象注入 request-scoped provider

    import { REQUEST } from '@nestjs/core';
    import { Request } from 'express';
    
    @Injectable({ scope: Scope.REQUEST })
    export class UsersService {
      constructor(@Inject(REQUEST) private readonly request: Request) {}
    }
    

    过时的答案

    无法将用户(或请求)直接注入服务。 Nest.js 还不支持请求范围的提供程序。这可能会随着版本 6 改变。在此之前,服务对请求一无所知。

    登录用户

    您可以创建一个custom decorator @User。使用装饰器比注入请求对象更可取,因为这样会失去很多嵌套的优势(如拦截器和异常过滤器)。

    export const User = createParamDecorator((data, req) => {
      return req.user;
    });
    

    然后像这样使用它:

    @UseGuards(AuthGuard()) 
    @Get(':id')
    async findOne(@Param('id') id, @User() user) {
       return await this.userService.findOne(id, user);
    }
    

    角色

    您可以创建一个RolesGuard,以确保登录用户具有所需的角色。详情请看answer

    【讨论】:

    • 我仍然需要将用户对象发送到服务。由于大部分逻辑都驻留在服务内部,这似乎是个坏主意。我已经有了 RolesGuard,但将其从示例中删除,因为它不是解决方案。假设我应该只能看到数据库中的一组数据。控制器中的入口点将是相同的,但服务应该过滤掉数据。然后我必须再次将用户从控制器发送到服务。
    • 角色守卫当然只是一个解决方案,如果你想完全限制访问。有时可能会导致具有不同访问级别的不同路线。但是,如果逻辑很复杂并且位于服务中,那么服务当然需要所有必需的数据才能传入。(最好使用装饰器而不是传入请求对象,否则拦截器,错误过滤器将不会’不会被调用。)正如我所写,这可能会在版本 6 中发生变化,但我还不知道细节。
    • 我试过你的V6解决方案。命令显示错误ReferenceError: Request is not defined。我做了import { REQUEST } from '@nestjs/core';
    • 请注意,作为per official docs,请求范围的提供程序将对应用程序性能产生影响。你也可以阅读this testimonial
    • 它也适用于 graphql 吗?
    猜你喜欢
    • 2021-11-17
    • 2020-11-23
    • 2021-09-02
    • 2012-06-26
    • 2020-10-10
    • 2019-12-01
    • 2019-12-22
    • 2021-08-16
    • 1970-01-01
    相关资源
    最近更新 更多