Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Howto get req.user in services in Nest JS

Tags:

In a controller, I add the user object with a guard, inject some service and call that service to get some response. I have removed a lot of code for brevity.

@Controller() @UseGuards(AuthGuard()) export class UserController() {    constructor(private readonly userService: UsersService) {    }     @Get(':id')    async findOne(@Param('id') id) {       return await this.userService.findOne(id);    } } 

Since I have the AuthGuard, I now know the user is logged in before entering :id route.

In the service I would do something like

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

But of course we want to have some checks that the logged in user has access to the user it is querying. The question is now how do I get the current logged in user. I can send it as a parameter from the controller, but since a lot of the backend would need security checked on the current user, I'm not sure that is a good idea.

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

Ideally, which doesn't work, I would be able to get it in the 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}});    } } 

Or perhaps through injection in the UserService constructor

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

So, is there a better way to send the user object through the backend than always sending the request object in each function call?

like image 966
flogvit Avatar asked Mar 04 '19 08:03

flogvit


People also ask

What is request in NestJS?

Request object Handlers often need access to the client request details. Nest provides access to the request object of the underlying platform (Express by default). We can access the request object by instructing Nest to inject it by adding the @Req() decorator to the handler's signature.

What is passport in NestJS?

Passport is the most popular node.js authentication library, well-known by the community and successfully used in many production applications. It's straightforward to integrate this library with a Nest application using the @nestjs/passport module.

How does dependency injection work in NestJS?

Dependency injection is an inversion of control (IoC) technique wherein you delegate instantiation of dependencies to the IoC container (in our case, the NestJS runtime system), instead of doing it in your own code imperatively.

What is injectable decorator in NestJS?

The @Injectable() decorator attaches metadata, which declares that CatsService is a class that can be managed by the Nest IoC container. By the way, this example also uses a Cat interface, which probably looks something like this: interfaces/cat.interface.ts.


1 Answers

Update March 2019

Since version v6, you can now inject the request object into a 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) {} } 

Outdated answer

It's not possible to inject the user (or request) directly into the service. Nest.js does not yet support request-scoped providers. This might change with version 6. Until then, a service does not know anything about a request.

Logged in user

You can create a custom decorator @User. Using a decorator is preferable over injecting the request object because then a lot of nest's advantages get lost (like interceptors and exception filters).

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

And then use it like this:

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

Roles

You can create a RolesGuard that makes sure the logged in user has the required roles. For details, see this answer.

like image 107
Kim Kern Avatar answered Oct 14 '22 03:10

Kim Kern