javascript - NestJS - Como usar RoleGuard com JWT?
Atualmente, consegui usar o AuthGuard com autenticação JWT, mas não consigo obter o user nos Roles.
Tentei seguir o exemplo dos gatos, mas nunca consigo definir o objeto user, podes ver na linha 14.
Este é o meu código:
// auth.controller.ts
@Controller('auth')
@UseGuards(RolesGuard)
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Get('token')
async createToken(): Promise<any> {
return await this.authService.createToken();
}
@Post()
@UseGuards(AuthGuard())
@Roles('admin')
findAll() {
// this route is restricted by AuthGuard
// JWT strategy
return 'Super important info';
}
}
// auth.module.ts
@Module({
imports: [
SharedModule,
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.registerAsync({
imports: [SharedModule],
useFactory: async (configService: ConfigService) => ({
secretOrPrivateKey: configService.get('SECRET_KEY'),
signOptions: {
expiresIn: configService.get('SECRET_KEY_EXPIRES'),
},
}),
inject: [ConfigService],
}),
],
controllers: [AuthController],
providers: [
AuthService,
JwtStrategy,
],
})
export class AuthModule {}
Todo o resto é exatamente como no exemplo do repositório. Alguma ideia de como conseguir definir os users?
Resposta #1
O AuthGuard() tem de ser executado antes do RolesGuard para que esteja autenticado e a propriedade user esteja definida.
Até onde sei, não há outra maneira de alterar a ordem dos seus guardas senão definindo-os como:
@UseGuards(AuthGuard(), RolesGuard)
Há uma discussão sobre uma API potencial para alterar a hierarquia de execução dos guardas neste problema.
Esta questão menciona uma solução alternativa:
Para este caso de uso, sinto que colocar a lógica de autenticação num middleware seria melhor, pois ele executa antes do guardião.
Resposta #2
Isto é o que funcionou para mim
jwt.guard.ts
import { AuthGuard } from '@nestjs/passport';
export class JwtGuard extends AuthGuard('jwt') {
constructor() {
super();
}
}
app.module.ts
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
],
providers: [
{
provide: APP_GUARD,
useClass: JwtGuard,
},
{
provide: APP_GUARD,
useClass: RoleGuard,
},
],
})
export class AppModule {}
role.decorator.ts
import { SetMetadata } from '@nestjs/common';
import { Role } from 'common/enums';
export const ROLE_KEY = 'role';
export const AllowRole = (role: Role) => SetMetadata(ROLE_KEY, role);
role.guard.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { ROLE_KEY } from 'common/decorators';
import { Role } from 'common/enums';
@Injectable()
export class RoleGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRole = this.reflector.getAllAndOverride<Role>(ROLE_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRole) {
return true;
}
const { user } = context.switchToHttp().getRequest();
console.log({ requiredRole });
console.log({ user });
return user.role === requiredRole;
}
}
