Прошло много дней, я думаю, это было решено. Я просто добавляю сюда свои два цента для будущих читателей.
Проблема заключается в экземплярах JwtModule и JwtStrategy. Они неправильно настроены. Вам необходимо передать алгоритмы, которые вы использовали бы для подписи и проверки токенов, вместе с ключами. Чтобы проверить, действительно ли токены генерируются с помощью RS256 al go, проверьте заголовок в токене по адресу https://jwt.io/. Вероятно, он покажет HS256, и поскольку ваш код не использовал правильный алгоритм для подписи токена. И это не удается, пока токен проверяется с использованием ключа publi c.
Чтобы правильно сгенерировать подписанные токены с помощью пары ключей RSA:
- Вам необходимо добавить алгоритм в signOptions как RS256 и передайте ключи publi c и private в конфигурации JwtModule.
- Тогда в рамках вашей службы вы должны сгенерируйте токен с помощью PRIVATE_KEY при подписании.
- JwtStrategy используется как Guard. Все, что он делает, это проверяет JWT на основе конфигурации. Он ожидает, что будет проверяться либо ключ симметрия c «секрет» , либо «publi c часть» асимметричного c ключа . Мы должны использовать PUBLIC_KEY. Здесь также необходимо указать алгоритмы проверки для проверки. Здесь мы также должны использовать RS256 , поскольку мы использовали его для генерации токена.
Auth Module
@Module({
imports: [
ConfigModule,
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => {
const options: JwtModuleOptions = {
privateKey: configService.get('JWT_PRIVATE_KEY'),
publicKey: configService.get('JWT_PUB LIC_KEY'),
signOptions: {
expiresIn: '3h',
issuer: '<Your Auth Service here>',
algorithm: 'RS256',
},
};
return options;
},
inject: [ConfigService],
}),
],
providers: [AuthService, JwtStrategy],
exports: [AuthService],
controllers: [AuthController],
})
export class AuthModule {}
Auth Service
@Injectable()
export class AuthService {
constructor(
private jwtService: JwtService,
) {}
async generateToken(
user: User,
signOptions: jwt.SignOptions = {},
): Promise<AuthJwtToken> {
const payload = { sub: user.id, email: user.email, scopes: user.roles };
return {
accessToken: this.jwtService.sign(payload, signOptions),
};
}
}
JwtStrategy
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private configService: ConfigService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: configService.get('JWT_PUBLIC_KEY'),
algorithms: ['RS256'],
});
}
async validate(payload: any) {
const { sub: userId, email, scopes: roles } = payload;
return {
id: userId,
email,
roles,
};
}
}
В других ваших микросервисах вы можете использовать ту же JwtStrategy, которую мы использовали в Модуль аутентификации.
Поскольку вы создаете распределенное приложение, вам необходимо поделиться PUBLIC_KEY с другими микросервисами, вручную добавив ключ или открыв его с помощью какой-либо конечной точки API. В любом случае вы должны использовать PUBLIC_KEY , чтобы другие службы могли проверить. Вы не должны делиться или предоставлять PRIVATE_KEY .
ПРИМЕЧАНИЕ : следующий код предполагает ConfigService, который предоставит пару ключей RSA в форме env . Настоятельно рекомендуется не проверять ключи в коде.