在一个守卫中使用条件多重策略

问题描述 投票:0回答:1

我正在使用 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)
nestjs passport.js
1个回答
0
投票

好像可以这样实现:

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()

© www.soinside.com 2019 - 2024. All rights reserved.