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

GraphQL联邦中集中式授权的实现方案咨询

集中式GraphQL联邦授权实现方案

针对你的场景,要实现supergraph层面的集中授权、让subgraph与权限逻辑完全解耦,可按以下步骤落地:

核心原则

  • supergraph作为唯一的权限校验入口,所有请求必须先经过supergraph的权限校验,再转发到对应subgraph
  • subgraph仅做IP白名单防护,只允许supergraph的IP访问,完全不处理业务权限逻辑
  • 权限规则集中管理,新增subgraph时只需扩展规则,无需修改subgraph代码

具体实现步骤

1. 在supergraph网关层添加全局权限拦截

以Apollo Gateway为例,利用网关的生命周期钩子在请求执行前完成权限校验。核心是解析用户身份(比如从请求头的Token中提取角色、用户ID),然后根据请求的字段/类型匹配权限规则。

代码示例:

const { ApolloGateway } = require('@apollo/gateway');
const { extractRequestedFields } = require('./utils/fieldExtractor'); // 自定义工具函数
const { getPermissionRule, checkUserPermission } = require('./utils/permissionChecker'); // 自定义工具函数

const gateway = new ApolloGateway({
  serviceList: [
    { name: 'posts', url: 'http://posts-subgraph:4001/graphql' },
    { name: 'users', url: 'http://users-subgraph:4002/graphql' },
    { name: 'products', url: 'http://products-subgraph:4003/graphql' }
  ],
  // 传递用户身份给subgraph(可选,subgraph无需用,但留作扩展)
  buildService({ url }) {
    return new RemoteGraphQLDataSource({
      url,
      willSendRequest({ request, context }) {
        request.http.headers.set('x-user-id', context.userId);
        request.http.headers.set('x-user-role', context.userRole);
      }
    });
  },
  // 权限校验核心逻辑
  async didResolveOperation({ request, context }) {
    // 1. 提取当前请求的所有字段路径(如Query.users, User.email, Query.products等)
    const requestedFields = extractRequestedFields(request);
    
    // 2. 遍历字段逐一校验权限
    for (const fieldPath of requestedFields) {
      const rule = getPermissionRule(fieldPath);
      if (!rule) {
        throw new Error(`未配置${fieldPath}的权限规则`);
      }

      switch (rule) {
        case 'allow-all':
          // posts公开访问,直接跳过
          break;
        case 'admin-or-authorized':
          // users数据:管理员或有权限用户可访问
          if (!context.userRole.includes('admin') && !await checkUserPermission(context.userId, fieldPath)) {
            throw new Error('无权访问用户数据');
          }
          break;
        case 'product-role-based':
          // products数据:匹配对应角色(如product_viewer、product_editor)
          if (!context.userRole.some(role => role.startsWith('product_'))) {
            throw new Error('无权访问产品数据');
          }
          break;
        case 'admin-or-self':
          // 用户自身数据:管理员或用户本人可访问
          const targetUserId = extractTargetUserId(request.variables); // 从请求参数提取目标用户ID
          if (!context.userRole.includes('admin') && context.userId !== targetUserId) {
            throw new Error('无权访问该用户信息');
          }
          break;
      }
    }
  }
});

2. 集中管理权限规则

把权限规则做成可配置的结构(可以存在JSON文件、数据库或配置中心),方便新增subgraph时快速扩展:

{
  "Query.posts": "allow-all",
  "Query.users": "admin-or-authorized",
  "User.*": "admin-or-self",
  "Query.products": "product-role-based",
  "Product.*": "product-role-based"
}

3. subgraph层面的IP防护

在每个subgraph的服务入口添加IP白名单中间件,只允许supergraph的IP访问,彻底阻断外部直接请求:

const express = require('express');
const app = express();

// IP白名单校验中间件
app.use((req, res, next) => {
  const allowedIPs = ['192.168.1.100']; // 替换为supergraph的实际IP
  const clientIP = req.ip || req.connection.remoteAddress.replace(/^.*:/, ''); // 处理IPv6格式

  if (!allowedIPs.includes(clientIP)) {
    return res.status(403).send('禁止直接访问');
  }
  next();
});

// 挂载Apollo Server
const { ApolloServer } = require('apollo-server-express');
const server = new ApolloServer({ schema: yourSubgraphSchema });
await server.start();
server.applyMiddleware({ app });

app.listen({ port: 4001 }, () => {
  console.log('Posts subgraph running');
});

4. 解决原指令失效问题

你之前在subgraph用指令失效,是因为GraphQL联邦合并supergraph schema时,默认不会保留subgraph的自定义指令。改用上述网关钩子的方式,不需要依赖schema指令,直接在请求执行前拦截校验,更适配联邦架构的集中授权需求。

扩展性说明

新增subgraph时,只需两步即可完成权限配置:

  1. 在supergraph的serviceList中添加新subgraph地址
  2. 在权限规则配置中新增对应字段的权限规则,无需修改任何subgraph代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 07:33:21