javascript - NestJS - Cách sử dụng RoleGuard với JWT?
Hiện tại, tôi đã quản lý để sử dụng AuthGuard với xác thực JWT, nhưng tôi không quản lý được để lấy user trên Roles.
Tôi đã cố gắng làm theo ví dụ của mèo, nhưng tôi không bao giờ định nghĩa được đối tượng user, bạn có thể thấy ở dòng 14.
Đây là mã của tôi:
// 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 {}
Phần còn lại hoàn toàn giống như ví dụ trong kho lưu trữ. Có cách nào để có thể lấy được users đã được định nghĩa không?
Câu trả lời #1
AuthGuard() phải chạy trước RolesGuard để bạn được xác thực và thuộc tính user được thiết lập.
Theo như tôi biết, không có cách nào khác để thay đổi thứ tự của các bảo vệ của bạn ngoài việc định nghĩa chúng như:
@UseGuards(AuthGuard(), RolesGuard)
Đang có một cuộc thảo luận về một API tiềm năng để thay đổi thứ tự thực thi của các guard trong vấn đề này.
Vấn đề này đề cập đến một giải pháp thay thế:
Đối với trường hợp sử dụng này, tôi cảm thấy việc đặt logic xác thực trong một middleware sẽ tốt hơn, vì nó chạy trước guard.
Câu trả lời #2
Đây là những gì đã có hiệu quả với tôi
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 {}
vai-tro.trang-tri.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);
vai_tro.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;
}
}
