使用graphql-shield防护Apollo子图时如何放行SubgraphIntrospectQuery
解决方案
你可以通过调整graphql-shield的权限规则,单独放行内省相关的查询操作,无需认证即可访问,两种实现方案如下:
方案1:显式枚举内省字段放行
graphql-shield的规则匹配优先级为「精确字段匹配 > 通配符匹配」,你可以直接对内省需要用到的字段单独设置公开权限:
const isAuthenticated = rule({ cache: 'contextual' })(async (parent, args, ctx, info) => { return ctx.isAuthenticated }) // 新增公开访问规则 const isPublic = rule({ cache: 'contextual' })(async () => true) const permissions = shield({ Query: { '*': and(isAuthenticated), // 放行GraphQL标准内省字段 __schema: isPublic, __type: isPublic, // 放行Apollo联邦子图专属内省字段 _service: isPublic }, Mutation: { '*': and(isAuthenticated) } })
方案2:动态识别内省请求放行
如果你不想手动枚举所有内省相关字段,可以新增规则自动识别内省请求直接放行,适配性更强:
const isAuthenticated = rule({ cache: 'contextual' })(async (parent, args, ctx, info) => { return ctx.isAuthenticated }) // 新增内省请求识别规则 const isIntrospectionRequest = rule({ cache: 'contextual' })(async (parent, args, ctx, info) => { // 匹配Rover子图内省的固定操作名 if (info.operation.name?.value === 'SubgraphIntrospectQuery') return true // 匹配所有GraphQL标准内省字段(均以__开头) if (info.fieldName.startsWith('__')) return true // 匹配Apollo联邦子图内省专属字段 if (info.fieldName === '_service') return true return false }) const permissions = shield({ Query: { '*': and(or(isIntrospectionRequest, isAuthenticated)) }, Mutation: { '*': and(isAuthenticated) } })
可选优化
如果需要避免公开暴露内省接口,可以在放行规则中增加额外校验逻辑,比如:
- 仅在非生产环境放行内省请求
- 校验请求来源IP属于你的构建集群网段
内容的提问来源于stack exchange,提问作者capiono
相关产品推荐
相关产品推荐

