Защитник резолвера в Nest
GraphQL отдаёт те же строки всем клиентам, хотя часть данных должна быть видна только при верном служебном заголовке. Без проверки на уровне операции лишний запрос сразу получит массив из памяти.
Класс реализует CanActivate
и через GqlExecutionContext
достаёт HTTP запрос из контекста
GraphQL. Его вешают на метод
резолвера через UseGuards.
В настройке модуля передают
контекст с req,
иначе заголовки не дойдут
до защитника.
Покажем на примере постов:
import {
CanActivate,
ExecutionContext,
Injectable,
} from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
@Injectable()
export class SecretGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const gqlContext = GqlExecutionContext.create(context);
const request = gqlContext.getContext().req;
return request.headers['x-secret'] === 'open';
}
}
Резолвер откроет список только после проверки:
import { UseGuards } from '@nestjs/common';
import { Query, Resolver } from '@nestjs/graphql';
import { SecretGuard } from './secret.guard.js';
@Resolver()
export class PostResolver {
titles = ['Первый', 'Второй'];
@Query(() => [String])
@UseGuards(SecretGuard)
posts(): string[] {
return this.titles;
}
}
Модуль передаст запрос в контекст и зарегистрирует оба класса:
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { PostResolver } from './post.resolver.js';
import { SecretGuard } from './secret.guard.js';
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: true,
context: ({ req }) => ({ req }),
}),
],
providers: [PostResolver, SecretGuard],
})
export class AppModule {}
Напишите защитник, который
пускает GraphQL только
со служебным заголовком,
и повесьте его на чтение списка
в WorkerResolver.