如何在 Graphql 中删除自省查询的身份验证
Posted
技术标签:
【中文标题】如何在 Graphql 中删除自省查询的身份验证【英文标题】:How to remove authentication for introspection query in Graphql 【发布时间】:2019-10-12 02:53:45 【问题描述】:所以这可能是一个非常基本的问题,所以请多多包涵。让我解释一下我在做什么以及我真正需要什么。
解释
我使用 ApolloGraphql(apollo-server-express npm 模块)创建了一个 graphql 服务器。
这里是代码 sn-p 给你一个想法。
api.js
import express from 'express'
import rootSchema from './root-schema'
.... // some extra code
app = express.router()
app.use(jwtaAuthenticator) // --> this code authenticates Authorization header
.... // some more middleware's added
const graphQLServer = new ApolloServer(
schema: rootSchema, // --> this is root schema object
context: context => context,
introspection: true,
)
graphQLServer.applyMiddleware( app, path: '/graphql' )
server.js
import http from 'http'
import express from 'express'
import apiRouter from './api' // --> the above file
const app = express()
app.use([some middlewares])
app.use('/', apiRouter)
....
....
export async function init ()
try
const httpServer = http.createServer(app)
httpServer
.listen(PORT)
.on('error', (err) => setTimeout(() => process.exit(1), 5000) )
catch (err)
setTimeout(() => process.exit(1), 5000)
console.log('Server started --- ', PORT)
export default app
index.js
require('babel-core')
require('babel-polyfill')
require = require('esm')(module/* , options */)
const server = require('./server.js') // --> the above file
server.init()
问题说明
我正在使用 node index.js 来启动应用程序。因此,应用程序期望 Authorization 标头(JWT 令牌)始终存在,即使对于 introspection 查询也是如此。但这不是我想要的,我希望即使没有令牌,内省查询也可以解决。这样任何人都可以看到文档。
请说明一下,并请指导什么是最好的方法。快乐编码:)
【问题讨论】:
【参考方案1】:.startsWith('query Introspection')
是不安全的,因为任何查询都可以命名为 Introspection
。
更好的方法是检查整个查询。
首先导入graphql并准备自省查询字符串:
const parse, print, getIntrospectionQuery = require('graphql');
// format introspection query same way as apollo tooling do
const introspectionQuery = print(parse(getIntrospectionQuery()));
然后在 Apollo Server 配置检查查询:
context: ( req ) =>
// allow introspection query
if (req.body.query === introspectionQuery)
return ;
// continue
【讨论】:
如果req.body.query
内省查询中的一些小调整与后端生成的inrospectionQuery
略有不同怎么办?或者这不太可能?
如果您在客户端和服务器中使用相同版本的graphql包,那么查询应该没有任何差异。【参考方案2】:
在 GraphQL 中有很多不同的方式来处理授权,如 the docs 所示:
为express
(或其他一些框架,如hapi
或koa
)添加中间件 检查单个解析器内部的授权 检查数据模型中的授权 使用custom directives
添加快速中间件非常适合防止未经授权访问您的整个架构。如果您想允许对某些字段进行未经身份验证的访问,但不允许其他字段,通常建议您使用上述方法之一将授权逻辑从框架层移动到 GraphQL 或数据模型层。
【讨论】:
谢谢指导,我去看看。【参考方案3】:所以我终于找到了解决方案,这就是我所做的。
我先告诉你,基本路径上添加了2个中间件。像这样:
app //--> this is express.Router()
.use(jwtMw) // ---> these are middlewares
.use(otherMw)
jwtMw 是检查用户身份验证的,由于即使 introspection 查询也属于此 MW,它曾经验证。所以,经过一番研究,我找到了这个解决方案:
jwtMw.js
function addJWTMeta (req, res, next)
// we can check for null OR undefined and all, then check for query Introspection, with better condition like with ignore case
if (req.body.query.trim().startsWith('query Introspection'))
req.isIntrospection = true
return next()
...
...
// ---> extra code to do authentication of the USER based on the Authorization header
export default addJWTMeta
otherMw.js
function otherMw (req, res, next)
if (req.isIntrospection) return next()
...
...
// ---> extra code to do some other context creation
export default otherMw
所以在 jwtMw.js 中,我们正在检查如果 查询是 Introspection,只需在 req 对象中添加一个变量并继续前进,并且在 jwtMw.js 之后的下一个中间件中,任何想要检查自省查询的人只需检查该 变量(在这种情况下是 isIntrospection) 以及它是否存在并且是 true,请继续。我们可以添加此代码并扩展到每个中间件,如果 req.isIntrospection 存在,则继续进行或执行实际处理。
编码愉快:)
【讨论】:
以上是关于如何在 Graphql 中删除自省查询的身份验证的主要内容,如果未能解决你的问题,请参考以下文章
GraphQL 架构文件应包含有效的 GraphQL 自省查询结果
如何使用 graphql 和护照设置身份验证但仍使用 Playground
React Apollo Link - 如何在使用 <Query /> 和 <Mutation /> 组件之外向 GraphQL 服务器查询身份验证令牌?