我正在使用 NestJs+Fastify+Passport。 默认情况下,我有带有 accessStrategy 的全局防护,如果使用装饰器 @SetAccessRight,我需要使其使用不同的策略。
所以,这是我的装饰器
import { SetMetadata } from '@nestjs/common';
import type { AccessRight } from '@enums';
const SetAccessRight = (request: AccessRight): MethodDecorator => SetMetadata('accessRight', request);
export default SetAccessRight;
和枚举:
export enum AccessRight {
public = 'public',
refresh = 'refresh',
confirm = 'confirm',
reset = 'reset',
}
它的工作原理如下:
@Get('refresh')
@SetAccessRight(AccessRight.refresh)
refresh() {}
现在说说我的守卫:
import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { Observable } from 'rxjs';
import { AccessRight } from '@enums';
import { JwtConfirmStrategy } from '../strategies/jwt-confirm.strategy';
import { JwtResetStrategy } from '../strategies/jwt-reset.strategy';
import { JwtRefreshStrategy } from '../strategies/jwt-refresh.strategy';
@Injectable()
export class JwtGuard extends AuthGuard('jwt-access') {
constructor(
private reflector: Reflector,
private confirmStrategy: JwtConfirmStrategy,
private resetStrategy: JwtResetStrategy,
private refreshStrategy: JwtRefreshStrategy,
) {
super();
}
handleRequest(err: any, user: any, info: any, context: any, status: any): any {
if (info) {
throw new UnauthorizedException(info.toString());
}
return super.handleRequest(err, user, info, context, status);
}
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
const accessRight = this.reflector.get<AccessRight>('accessRight', context.getHandler());
switch (accessRight) {
case AccessRight.public:
return true;
case AccessRight.confirm:
// ??? use confirm strategy ???
break;
case AccessRight.refresh:
// ??? use refresh strategy ???
return true;
}
return super.canActivate(context);
}
}
因此,如果端点不使用 @SetAccessRight() 装饰器,JwtGuard 应默认使用“jwt-access”策略,如果使用装饰器,则应使用不同的策略。 我不知道如何做到正确,因为这不仅仅是链接策略,而是有条件使用,而且我在任何地方都找不到任何有关如何做到这一点的信息,就好像我是世界上第一个尝试这样做的人一样那个。
我尝试以这种方式执行策略:
this.refreshStrategy.authenticate(context.switchToHttp().getRequest());
但我收到此错误:
/.../node_modules/passport-jwt/lib/strategy.js:111
return self.error(err);
^
TypeError: self.error is not a function
at verified (/.../node_modules/passport-jwt/lib/strategy.js:111:41)
at JwtRefreshStrategy.callback [as _verify] (/.../node_modules/@nestjs/passport/dist/passport/passport.strategy.js:20:21)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
好像可以这样实现:
class RefreshGuard extends AuthGuard('jwt-refresh') {}
class ConfirmGuard extends AuthGuard('jwt-confirm') {}
class ResetGuard extends AuthGuard('jwt-reset') {}
...
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
const accessRight = this.reflector.get<AccessRight>('accessRight', context.getHandler());
switch (accessRight) {
case AccessRight.public:
return true;
case AccessRight.confirm:
return new ConfirmGuard().canActivate(context);
case AccessRight.refresh:
return new RefreshGuard().canActivate(context);
case AccessRight.reset:
return new ResetGuard().canActivate(context);
default:
return super.canActivate(context);
}
}
现在,你不必在每条路线上使用
@UseGuards()
装饰器,只需 @SetAccessRight()