Nest.JS使用AuthGuard作为GraphQL的中间件

时间:2018-08-21 08:40:43

标签: passport.js graphql nestjs

我正在尝试使用passwordJS保护我的GraphQL端点,以便对该端点的每个调用都使用AuthGuard来验证令牌并根据request.user设置用户,就像在使用以下代码的控制器中所做的那样:

@Get('findAll')
@UseGuards(AuthGuard('jwt'))
findAll(@Req() request): Promise<Array<Thing>> {
    return this.thingService.findByUser(request.user.email);
}

我想在graphQL端点中使用它,它是这样创建的:

consumer
    .apply(graphiqlExpress({ endpointURL: '/graphql' }))
    .forRoutes('/graphiql')
    .apply(
        graphqlExpress(req => ({ schema, rootValue: req })),
        ¿?,
    )
    .forRoutes('/graphql');

我想我可以像在graphqlExpress函数之后一样将其设置为中间件函数,但是我没有成功。有什么想法吗?

提前谢谢!

修改

作为一种解决方法,我已经实现了Nest Docs上提出的解决方案,该解决方案在每个必须保护的查询/突变中都使用@UseGuard。

但是,我想保护整个端点,这样就不会为每个受保护的解析程序调用防护,而是在主请求上仅调用一次。这有可能吗?

2 个答案:

答案 0 :(得分:1)

从技术上讲这是可能的,但是写起来是很草率的,而且绝对不能保证它可以与Fastify一起使用,所以请注意。功能的实质来自于您实现中间件的模块。我最后用AppModule(我不建议这样做(至少不是全部代码的全部))进行了所有操作,但是仍然有效。

您需要使防护罩为custom provider,以便可以将其插入任何上下文中。

然后,您需要使用ExecutionContext模拟req, res, next。如果您想要输入安全性,这说起来容易做起来难,但是如果您不关心这个(我不是这样做的话),那么请给as any打个电话,然后每天称呼它。

此后,在中间件使用者中,运行apply并将this.guard.canActivate与创建的模拟ExecutionContext一起使用。将此中间件asyncawait进行canActivate调用。检查它是否返回为true,如果不是,则返回throw new <ErrorOfYourChoice>()并动臂。设置好了。代码看起来(大概)是这样的:

import {
  BadRequestException,
  CanActivate,
  Inject,
  MiddlewareConsumer,
  Module,
  NestModule,
} from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AppResolver } from './app.resolver';
import { GraphQLModule } from '@nestjs/graphql';
import { JwtModule } from '@nestjs/jwt';
import { AuthGuard, PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';

@Module({
  imports: [
    GraphQLModule.forRoot({
      autoSchemaFile: true,
    }),
    JwtModule.register({ secret: 'secret' }),
    PassportModule.register({ defaultStrategy: 'jwt' }),
  ],
  controllers: [AppController],
  providers: [
    AppService,
    AppResolver,
    JwtStrategy,
    { provide: 'CustomGuard', useClass: AuthGuard() },
  ],
})
export class AppModule implements NestModule {
  constructor(@Inject('CustomGuard') private readonly guard: CanActivate) {}

  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(async (req, res, next) => {
        const canActivate = await this.guard.canActivate({
          switchToHttp: () => ({
            getRequest: () => req,
            getResponse: () => res,
            getNext: () => next,
          }),
        } as any);
        if (canActivate) {
          next();
        } else {
          throw new BadRequestException();
        }
      })
      .forRoutes('graphql');
  }
}

您可以检查this repository是否已连接并正常工作。使用POST /login -d 'username=test1&password=changeme'登录,获取JWT并随意使用它。

答案 1 :(得分:-1)

<块引用>

但是,我想保护整个端点,这样就不会为每个受保护的解析器调用保护,而只在主请求上调用一次。这甚至可能吗?

通过在此处使用来自 NestJS 的参考全局方法,我能够获得一个中间件函数来解析每个查询/突变:https://docs.nestjs.com/graphql/field-middleware#global-field-middleware