Issue
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?
Solution
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.
Answered By - Kim Kern
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.