如何在@apollo/server中集成graphql-shield实现权限控制
在Apollo Server v4中使用graphql-shield实现权限控制
一、适配Apollo Server v4的实现方式
Apollo Server v4不会直接暴露自动生成的Schema,因此需要手动构建可执行Schema并应用graphql-shield中间件,具体步骤如下:
1. 导入必要工具
首先从@graphql-tools/schema导入makeExecutableSchema,若未安装该依赖,执行npm install @graphql-tools/schema添加。
2. 定义权限规则
先编写符合业务需求的shield规则,比如验证用户登录状态、角色权限等:
import { shield, rule, and } from "graphql-shield"; // 验证用户是否已登录的规则 const isAuthenticated = rule()(async (parent, args, context) => { // 替换为你的实际token解析/用户验证逻辑,比如JWT解析 const user = await validateToken(context.token); return !!user; }); // 验证用户是否为管理员的规则 const isAdmin = rule()(async (parent, args, context) => { const user = await validateToken(context.token); return user?.role === "ADMIN"; }); // 权限规则映射 const permissions = shield({ Query: { // 仅登录用户可查看个人信息 me: isAuthenticated, // 仅管理员可查看用户列表 userList: isAdmin, }, Mutation: { // 仅登录用户可更新个人资料 updateProfile: isAuthenticated, // 仅管理员可创建用户 createUser: isAdmin, }, });
3. 修改原代码,应用中间件
调整初始化流程,先构建基础Schema,再注入权限中间件,最后传给ApolloServer:
import * as dotenv from "dotenv"; import mongoose from "mongoose"; import typeDefs from "./graphql/typeDefs.js"; import resolvers from "./graphql/resolvers.js"; import { makeExecutableSchema } from "@graphql-tools/schema"; // 新增导入 import { ApolloServer } from "@apollo/server"; import { expressMiddleware } from "@apollo/server/express4"; import { ApolloServerPluginDrainHttpServer } from "@apollo/server/plugin/drainHttpServer"; import express from "express"; import http from "http"; import pkg from "body-parser"; import cors from "cors"; import { applyMiddleware } from "graphql-middleware"; import { shield, rule } from "graphql-shield"; dotenv.config(); const { json } = pkg; const MONGODB = process.env.MONGODB; // 1. 构建基础可执行Schema const baseSchema = makeExecutableSchema({ typeDefs, resolvers }); // 2. 定义权限规则(替换为你的实际规则) const isAuthenticated = rule()(async (parent, args, context) => { return context.token !== ""; // 示例:简单验证token存在,实际需解析验证 }); const permissions = shield({ Query: { me: isAuthenticated, }, Mutation: { updateUser: isAuthenticated, }, }); // 3. 将权限中间件应用到Schema const schemaWithPermissions = applyMiddleware(baseSchema, permissions); const app = express(); const httpServer = http.createServer(app); // 4. 初始化ApolloServer时传入处理后的Schema const server = new ApolloServer({ schema: schemaWithPermissions, // 替换原有的typeDefs和resolvers参数 plugins: [ApolloServerPluginDrainHttpServer({ httpServer })], }); await mongoose.connect(MONGODB, { useNewUrlParser: true, }); await server.start(); app.use( "/graphql", cors({ origin: ["https://studio.apollographql.com", process.env.FRONTEND_DEV_URL], }), json(), expressMiddleware(server, { context: ({ req }) => ({ token: req.headers.authorization || "", }), }) ); await new Promise((resolve) => httpServer.listen({ port: process.env.PORT || 4000 }, resolve) ); console.log(`🚀 Server ready `);
二、官方文档「真实世界示例」中文翻译
真实世界示例
假设你有一个博客应用,需求如下:
- 所有用户均可查看帖子和评论
- 仅帖子作者可编辑/删除自己的帖子
- 仅评论作者可删除自己的评论
- 登录用户可创建帖子和评论
首先定义基础规则:
const isAuthenticated = rule()(async (parent, args, ctx) => { return ctx.user !== null; }); const isPostAuthor = rule()(async (parent, { id }, ctx) => { const post = await ctx.prisma.post.findUnique({ where: { id } }); return post.authorId === ctx.user.id; }); const isCommentAuthor = rule()(async (parent, { id }, ctx) => { const comment = await ctx.prisma.comment.findUnique({ where: { id } }); return comment.authorId === ctx.user.id; });然后定义权限映射:
const permissions = shield({ Query: { posts: allow, // 允许所有用户访问 post: allow, comments: allow, }, Mutation: { createPost: isAuthenticated, createComment: isAuthenticated, updatePost: and(isAuthenticated, isPostAuthor), deletePost: and(isAuthenticated, isPostAuthor), deleteComment: and(isAuthenticated, isCommentAuthor), }, });最后将中间件应用到Schema:
const schema = applyMiddleware(executableSchema, permissions);
三、替代方案推荐
若graphql-shield的适配成本过高,可考虑以下更灵活的权限控制方案:
1. Apollo Server原生权限控制
- Resolver内验证:在需要权限的resolver开头添加验证逻辑,比如检查context中的用户身份和权限。
- 自定义Directive:在typeDefs中用
@auth等标记需要权限的字段,通过Apollo Server的directives选项实现验证逻辑。
2. Envelop权限插件
Envelop是The Guild推出的模块化GraphQL中间件框架,提供官方的@envelop/authorization权限插件,适配Apollo Server v4,支持更灵活的中间件组合,且维护更活跃。
内容的提问来源于stack exchange,提问作者WildThing
相关产品推荐
相关产品推荐

