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?
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.
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.
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.
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.
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) {} }
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.
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); }
You can create a RolesGuard
that makes sure the logged in user has the required roles. For details, see this answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With