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

Apollo Federation网关如何实现子图动态身份认证与凭证传递

Apollo Gateway 子图动态身份认证最佳实践

完全不需要访问私有serviceMap属性,基于Apollo官方公开的扩展点即可实现,同时兼容手动配置子图和Apollo托管联邦两种部署模式:

实现核心逻辑

  • 利用buildService入参自带的子图name属性标识每个子图数据源,避免硬编码URL匹配
  • 网关上下文提前拉取当前用户所有子图的访问凭证,通过上下文传递给数据源钩子
  • 在RemoteGraphQLDataSource的willSendRequest钩子中匹配当前子图标识,注入对应凭证

完整代码实现

import { ApolloServer } from '@apollo/server';
import { ApolloGateway, RemoteGraphQLDataSource } from '@apollo/gateway';
import { GraphQLRequest } from 'apollo-server-types';

// 自定义数据源,绑定子图名称
class AuthenticatedDataSource extends RemoteGraphQLDataSource {
  // 接收子图name作为初始化参数
  constructor(config: { url: string, serviceName: string }) {
    super({ url: config.url });
    this.serviceName = config.serviceName;
  }

  private serviceName: string;

  async willSendRequest({ request, context }: { request: GraphQLRequest, context: any }) {
    // 直接从上下文取当前子图对应的凭证,不需要匹配URL
    const userServiceToken = context.userServiceTokens?.[this.serviceName];
    if (userServiceToken) {
      request.http?.headers.set('Authorization', `Bearer ${userServiceToken}`);
    }
  }
}

const main = async () => {
  const gateway = new ApolloGateway({
    // 不管是手动配置serviceList还是托管联邦模式,buildService的入参都会携带子图的name和url
    buildService: ({ name, url }) => {
      // 给每个子图数据源绑定对应的子图名称
      return new AuthenticatedDataSource({ url, serviceName: name });
    },
    // 也支持托管联邦模式,不需要手动写serviceList
    // serviceList: [
    //   { name: 'service1', url: 'http://localhost:3001' },
    //   { name: 'service2', url: 'http://localhost:3002' },
    // ]
  });

  const server = new ApolloServer({ gateway });

  await server.listen({ port: 3000 }, async ({ url }) => {
    console.log(`Apollo Gateway ready at ${url}`);
  });
}

上下文用户凭证拉取示例

在Apollo Server的上下文构造函数中统一拉取当前用户的所有子图凭证,可以根据需要加缓存降低数据库压力:

const server = new ApolloServer({
  gateway,
  // 上下文构造钩子,每个请求执行一次
  context: async ({ req }) => {
    // 先做网关层的用户身份校验
    const userId = verifyUserToken(req.headers.authorization);
    if (!userId) throw new Error('身份认证失败');

    // 批量拉取当前用户所有子图的访问凭证
    const userServiceTokens = await getUserAllServiceTokens(userId);
    return { userServiceTokens };
  }
});

额外优化建议

  • 可以给用户的子图凭证加本地缓存,缓存key绑定用户ID,过期时间和凭证有效期对齐,避免每次请求查库
  • 不需要传递给子图的敏感信息不要存入上下文,避免日志泄露
  • 如果子图的认证规则不同,可以在AuthenticatedDataSource中加自定义配置项单独处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 07:45:04