我喜欢实施多个名为“passport-JWT”的策略,每个策略都有自己的
secret
。有什么办法可以实现吗?
据我从文档了解到,在模块初始化期间只能注册一个秘密:
@Module({
imports: [
UsersModule,
PassportModule,
JwtModule.register({
secret: jwtConstants.secret,
signOptions: { expiresIn: '60s' },
}),
],
providers: [AuthService, LocalStrategy],
exports: [AuthService, JwtModule],
})
为了允许注册同一服务的多个变体,您将需要使用自定义提供程序和包装器模块
JwtModule
。它可能看起来像这样:
@Module({
imports: [JwtModule.register({
secret: secret1,
signOptions: { expiresIn: '60s' },
})],
providers: [{
provide: 'JwtSecret1Service',
useExisting: JwtService,
}],
exports: ['JwtSecret1Service'],
})
export class JwtSecret1Module {}
现在您可以使用
@Inject('JwtSecret1Service')
来使用此特定配置,只要 JwtSecret1Module
已添加到使用模块的 imports
即可。您可以根据需要使用任意多个 JwtService
变体来完成此操作,并且每个变体都将保留其自己的配置
基本上,当您创建策略时,您可以为策略名称添加第二个参数。然后您可以在
AuthGuard
上指定您需要的 JWT 策略。
// auth/strategy/jwt-access.strategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
@Injectable()
export class AccessTokenStrategy extends PassportStrategy(Strategy, 'jwt-access-token') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: 'access-token-secret',
});
}
async validate(payload: any) {
// your validate implementation here
return {};
}
}
// auth/guard/jwt-access-auth.guard.ts
import { ExecutionContext, Injectable } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class AccessTokenAuthGuard extends AuthGuard('jwt-access-token') {
getRequest(context: ExecutionContext) {
const ctx = GqlExecutionContext.create(context);
return ctx.getContext().req;
}
}
您可以保持
auth.module.ts
不变,在您的服务中您可以使用jwtService.sign
的选项参数,如下面的代码所示
@Injectable()
export class AuthService {
...
login(user: User) {
return {
access_token: this.jwtService.sign({ /* object to sign */ }),
refresh_token: this.jwtService.sign(
{ /* object to sign */ }
{ secret: 'refresh-token-secret', expiresIn: '14d' },
),
};
}
}
几天前我也做了同样的事情。 我创建了刷新令牌和访问令牌。 这是应用程序模块:
imports: [..., JwtModule.register({})]
我就这样注册了JwtModule。 如果您想创建访问令牌: 访问令牌策略:
export class AccessStrategy extends PassportStrategy(Strategy, 'access') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: JwtConstants.access_token_secret,
});
}
validate(payload: any) {
return payload;
}
}
如果您想创建访问令牌:
accessToken(userId: number, username: string) {
const token = this.jwtService.signAsync(
{
sub: userId,
username: username,
},
{
secret: JwtConstants.access_token_secret,
expiresIn: 60,
},
);
if (token) {
return token;
}
return null;
}
您可以对刷新令牌或其他令牌执行相同的操作
我最近创建了一个包来管理它,扩展了 Passport-jwt 以允许将 Passport-jwt 配置数组传递给构造函数。当请求到达时,使用标准的 Passport-jwt 代码并行检查每个配置,以查看 JWT 是否应该获得授权。
这是软件包:https://www.npmjs.com/package/@mestrak/passport-multi-jwt。
在 NestJS 中,您可以在
jwt.strategy.ts
中执行类似的操作(或者任何您的策略设置文件的名称。
import { ExtractJwt, Strategy } from '@mestrak/passport-multi-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super([{
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: 'a_secret_key',
},
{
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: 'another_secret_key',
}]);
}
async validate(payload: any) {
return payload;
}
}
添加所需的防护,如 AuthGuard(['jwt', 'jwt_2']),然后像此导出类 JwtStrategy 扩展 PassportStrategy(Strategy, 'jwt') {}
导出类 JwtStrategy2 扩展 PassportStrategy(Strategy, 'jwt2') {}