Nest.JS 使用 AuthGuard 作为 GraphQL 的中间件
Posted
技术标签:
【中文标题】Nest.JS 使用 AuthGuard 作为 GraphQL 的中间件【英文标题】:Nest.JS use AuthGuard as Middleware for GraphQL 【发布时间】:2019-01-27 09:54:53 【问题描述】:我正在尝试使用 passportJS 来保护我的 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。
但是,我想保护整个端点,这样就不会为每个受保护的解析器调用警卫,而只会在主请求上调用一次。这甚至可能吗?
【问题讨论】:
如果您仍然像在 Nest 中的 REST 应用程序中一样使用模块,您可以将 Guard 注册为提供程序 - 请参阅此处的示例以了解整个应用程序 docs.nestjs.com/guards#role-based-authentication 。这能解决你的问题吗? 【参考方案1】:但是,我想保护整个端点,这样就不会为每个受保护的解析器调用警卫,而只会在主请求上调用一次。这甚至可能吗?
通过在这里使用 NestJS 的参考全局方法,我能够获得一个中间件函数来解决每个查询/突变:https://docs.nestjs.com/graphql/field-middleware#global-field-middleware。
【讨论】:
【参考方案2】:这在技术上是可行的,但是写起来很草率,而且绝对不能保证它可以与 Fastify 一起使用,所以请注意。功能的核心来自实现中间件的模块。我最终用我不建议的AppModule
完成了这一切(至少不是那里的所有代码),但它仍然有效。
您需要将守卫设为custom provider,以便可以将其注入到任何上下文中。
然后您需要使用req, res, next
模拟ExecutionContext
。如果你想要类型安全,这说起来容易做起来难,但如果你不关心这个(我不关心这个),那么就打一个 as any
并收工。
之后,在中间件使用者中运行 apply
并使用 this.guard.canActivate
和您创建的模拟 ExecutionContext
。将此中间件 async
和 await
设为 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 并随心所欲地使用它。
【讨论】:
嗨 Jay 解决方案不起作用。您还有其他建议吗? 我的建议是不要使用这种方法。它草率且难以管理。相反,只需正常使用守卫,而不是作为中间件 我自己喜欢这个问题,正在寻找一种方法来避免在每个解析器上使用防护。 然后告诉我什么不起作用,而不是“它不起作用”,因为当我为它创建 repo 时它起作用了 决定采纳您的建议并使用最佳方法。谢谢以上是关于Nest.JS 使用 AuthGuard 作为 GraphQL 的中间件的主要内容,如果未能解决你的问题,请参考以下文章
Nest.js 中使用 @nestjs/passport 的可选身份验证
Nest.js Auth Guard JWT 身份验证不断返回 401 未授权
Nest JS / MongoDB - 地理空间索引在部署的服务器上不起作用
如何将firebase时间戳与graphql nest js一起使用?