Vyhledávání na webu

javascript - NestJS - Jak používat RoleGuard s JWT?


V současné době se mi podařilo použít AuthGuard s JWT autentizací, ale nedaří se mi získat user na Roles.

Snažil jsem se následovat příklad kočky, ale nikdy se mi nepodaří definovat objekt user, jak můžete vidět na řádku 14.

Toto je můj kód:

// 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 {}

Všechno ostatní je přesně jako v příkladu v repozitáři. Máte nějaký nápad, jak získat definované users?

Odpověď č. 1

AuthGuard() musí běžet před RolesGuard, aby bylo zajištěno, že jste autentizováni a vlastnost user je nastavena.

Pokud vím, neexistuje žádný jiný způsob, jak změnit pořadí vašich ochránců, než je definovat jako:

@UseGuards(AuthGuard(), RolesGuard)

V této záležitosti probíhá diskuse o možné API pro změnu pořadí vykonávání strážců.

Tato otázka zmiňuje alternativní řešení:

Pro tento případ použití mi připadá lepší umístit autentizační logiku do middleware, protože se spouští před guardem.

Odpověď č. 2

Tohle na mě fungovalo

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;
  }
}