如何检查GraphQL查询中的权限和其他条件?

我如何检查用户是否有权查看查询某些内容? 我不知道如何做到这一点。

  • args ? 那将如何工作?
  • resolve() ? 看看用户是否有权限,并以某种方式消除/改变一些参数?

例:

如果用户是“访问者”,他只能看到公共职位,“pipe理员”可以看到一切。

 const userRole = 'admin'; // Let's say this could be "admin" or "visitor" const Query = new GraphQLObjectType({ name: 'Query', fields: () => { return { posts: { type: new GraphQLList(Post), args: { id: { type: GraphQLString }, title: { type: GraphQLString }, content: { type: GraphQLString }, status: { type: GraphQLInt // 0 means "private", 1 means "public" }, }, // MongoDB / Mongoose magic happens here resolve(root, args) { return PostModel.find(args).exec() } } } } }) 

更新 – Mongoose模型看起来像这样:

 import mongoose from 'mongoose' const postSchema = new mongoose.Schema({ title: { type: String }, content: { type: String }, author: { type: mongoose.Schema.Types.ObjectId, // From user model/collection ref: 'User' }, date: { type: Date, default: Date.now }, status: { type: Number, default: 0 // 0 -> "private", 1 -> "public" }, }) export default mongoose.model('Post', postSchema) 

您可以在parsing函数或模型图层中检查用户的权限。 以下是你必须采取的步骤:

  1. 在执行查询之前validation用户。 这取决于你的服务器,通常发生在graphql之外,例如通过查看与请求一起发送的cookie。 有关如何使用Passport.js执行此操作的更多详细信息,请参阅此中文文章 。
  2. 将经过身份validation的用户对象或用户标识添加到上下文中。 在express-graphql中,你可以通过context参数来实现:

     app.use('/graphql', (req, res) => { graphqlHTTP({ schema: Schema, context: { user: req.user } })(req, res); } 
  3. 在parsing函数中使用上下文,如下所示:

     resolve(parent, args, context){ if(!context.user.isAdmin){ args.isPublic = true; } return PostModel.find(args).exec(); } 

您可以直接在parsing函数中进行授权检查,但是如果您有模型图层,则强烈build议通过将用户对象传递到模型图层来实现它。 这样你的代码就会更加模块化,更容易重用,而且你不用担心在某个parsing器中忘记了一些检查。

关于授权的更多背景,看看这篇文章(也是我自己写的): 在GraphQL中validation – 第2部分

帮助我们解决授权问题的一种方法是将parsing器视为中间件的组成部分。 上面的例子很好,但是随着你的授权机制变得更加先进,这个例子会变得不成规模。

一个parsing器作为中间件组合的例子可能看起来像这样:

 type ResolverMiddlewareFn = (fn: GraphQLFieldResolver) => GraphQLFieldResolver; 

ResolverMiddlewareFn是一个函数,它接受一个GraphQLFieldResolver并返回一个GraphQLFieldResolver 。

为了组成我们的parsing器中间件function,我们将使用(你猜对了)写作function! 这里是一个用javascript实现的组合实例 ,但是你也可以在ramda和其他函数库中find合成函数。 撰写让我们结合简单的function,使更复杂的function。

回到GraphQL权限问题让我们看一个简单的例子。 假设我们要loginparsing器,授权用户,然后运行肉和土豆。 撰写让我们结合这三个部分,使我们可以轻松地testing和重新使用它们在我们的应用程序。

 const traceResolve = (fn: GraphQLFieldResolver) => async (obj: any, args: any, context: any, info: any) => { const start = new Date().getTime(); const result = await fn(obj, args, context, info); const end = new Date().getTime(); console.log(`Resolver took ${end - start} ms`); return result; }; const isAdminAuthorized = (fn: GraphQLFieldResolver) => async (obj: any, args: any, context: any, info: any) => { if (!context.user.isAdmin) { throw new Error('User lacks admin authorization.'); } return await fn(obj, args, context, info); } const getPost = (obj: any, args: any, context: any, info: any) => { return PostModel.find(args).exec(); } const getUser = (obj: any, args: any, context: any, info: any) => { return UserModel.find(args).exec(); } // You can then define field resolve functions like this: postResolver: compose(traceResolve, isAdminAuthorized)(getPost) // And then others like this: userResolver: compose(traceResolve, isAdminAuthorized)(getUser)