You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Apollo Server中配置GraphQL默认拒绝访问并对接外部授权服务

GraphQL 默认锁定所有操作并通过指令开放权限的实现方案

核心思路

默认拒绝所有查询(queries)和变更(mutations),仅对标记了自定义授权指令的字段,触发外部授权服务校验,校验通过后才允许访问。


步骤1:定义自定义授权指令

在GraphQL Schema中声明@authorize指令,用于标记需要开放权限的字段:

# 定义授权指令,作用于字段定义
directive @authorize on FIELD_DEFINITION

# 示例Schema:只有标记@authorize的字段可被访问
type Query {
  # 该查询默认被锁定
  restrictedQuery: String
  # 该查询需通过授权校验才能访问
  allowedQuery: String @authorize
}

type Mutation {
  restrictedMutation: String
  allowedMutation: String @authorize
}

步骤2:实现指令校验与全局默认拦截

以Apollo Server(Node.js)为例,通过Schema指令和全局插件实现逻辑:

1. 实现@authorize指令的授权逻辑

const { SchemaDirectiveVisitor } = require('apollo-server');
const { defaultFieldResolver } = require('graphql');

class AuthorizeDirective extends SchemaDirectiveVisitor {
  visitFieldDefinition(field) {
    const originalResolve = field.resolve || defaultFieldResolver;

    // 重写字段解析器,先调用外部授权服务
    field.resolve = async (...args) => {
      // 从上下文或参数中获取用户身份等信息,传入外部授权服务
      const { context } = args[2];
      const isAuthorized = await callExternalAuthorizeService(context.user.id, field.name);

      if (!isAuthorized) {
        throw new Error('权限校验失败,无法访问该操作');
      }

      // 授权通过,执行原解析逻辑
      return originalResolve.apply(this, args);
    };
  }
}

// 模拟外部授权服务调用
async function callExternalAuthorizeService(userId, operationName) {
  // 替换为实际的外部服务调用逻辑
  return await fetch('https://your-authorize-service.com/check', {
    method: 'POST',
    body: JSON.stringify({ userId, operationName })
  }).then(res => res.json());
}

2. 全局拦截无授权指令的字段

通过Apollo插件实现全局校验,所有未标记@authorize的字段直接拒绝访问:

const { ApolloServer } = require('apollo-server');
const typeDefs = require('./your-schema');
const resolvers = require('./your-resolvers');

const server = new ApolloServer({
  typeDefs,
  resolvers,
  // 注册自定义指令
  schemaDirectives: {
    authorize: AuthorizeDirective,
  },
  plugins: [
    {
      async requestDidStart() {
        return {
          async executionDidStart() {
            return {
              async willResolveField({ field }) {
                // 检查当前字段是否带有@authorize指令
                const hasAuthorizeDirective = field.astNode.directives?.some(
                  dir => dir.name.value === 'authorize'
                );

                // 无指令则直接抛出权限错误
                if (!hasAuthorizeDirective) {
                  throw new Error('该操作未开放权限,请联系管理员');
                }
              },
            };
          },
        };
      },
    },
  ],
});

server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

关键注意事项

  • 性能优化:对外部授权服务的结果做缓存(如Redis),避免重复调用影响接口响应速度
  • 灵活授权:可扩展指令参数,比如@authorize(roles: ["admin", "editor"]),让授权逻辑更精细化
  • 嵌套字段处理:根据业务需求,可调整全局拦截逻辑,比如允许已授权父字段的子字段自动继承权限

内容的提问来源于stack exchange,提问作者Laura

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 05:55:19