首页/新闻资讯/正文详情

使用 Prisma 与 graphql-yoga 实现 GraphQL API 权限控制:从数据模型到 Resolver 的完整实战

发布时间:2026/9/23 21:35:38 来源:云帆数科 栏目:资讯中心
使用 Prisma 与 graphql-yoga 实现 GraphQL API 权限控制:从数据模型到 Resolver 的完整实战
后端数据库GraphQL【免费下载链接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]项目地址https://gitcode.com/gh_mirrors/pr/prisma1点击查看免费下载在基于 Prisma 与graphql-yoga构建的 GraphQL 服务中权限控制并不是数据库层面的功能而是由开发者在自己编写的 resolver 中实现的数据访问检查。本文以官方教程为基础完整演示如何从零搭建一个带认证的 GraphQL 服务器通过修改数据模型引入ADMIN角色并利用prisma-binding提供的exists函数逐个为feed、drafts、post、publish、deletePost五个查询/变更实现细粒度的访问控制。读完本文你将掌握应用层权限校验这一 Prisma 时代标准实践并能直接将其复用到自己的 GraphQL 服务中。背景Prisma 时代的权限控制思路在 Graphcool Framework 时代权限规则permission queries被声明式地配置在框架内部。而到了 Prisma 时代这一职责被明确移交到了应用层——也就是你的 GraphQL 服务器代码中。正如仓库文档 Authentication Authorization 所总结的User authentication and permission rules are now implemented in the application layer of your GraphQL server. Theexistsfunction from theprisma-bindingpackage serves a similar purpose as permissions queries inside the Graphcool Framework.这意味着每当你需要限制某个操作时就在对应的 resolver 里先做一次数据访问检查检查通过后才把操作转发给底层的 Prisma 数据库服务。而prisma-binding包在node-advanced样板工程中暴露为ctx.db正是这一转发的关键桥梁。引导 GraphQL 服务器安装 GraphQL CLI在开始之前需要先安装 GraphQL CLI。打开终端执行npm install -g graphql-cli说明本教程不需要单独安装 Prisma CLI因为node-advanced样板工程将prisma列为development dependency因此可以通过yarn前缀运行它的命令例如yarn prisma deploy或yarn prisma playground。如果你已在全局安装prismanpm install -g prisma则可以省略yarn前缀。创建项目在任意目录下运行graphql create permissions-example --boilerplate node-advanced当被询问要将 Prisma 服务部署到哪个cluster时选择一个公共演示集群prisma-eu1或prisma-us1。注意你也可以在本地部署 Prisma 服务但这要求机器上装有 Docker。本教程选用公共演示集群以保持流程简单直接。该命令会创建名为permissions-example的新目录其中包含基于graphql-yoga的 GraphQL 服务器源码以及对应 Prisma 数据库服务的配置文件。node-advanced样板工程自带开箱即用的认证功能signup / login并且预配置好了prisma-binding与若干示例 resolver——这正是我们接下来要逐步改造的基础。这个 GraphQL 服务器基于以下数据模型对应 Prisma 服务的database/datamodel.graphqltype Post { id: ID! unique createdAt: DateTime! updatedAt: DateTime! isPublished: Boolean! default(value: false) title: String! text: String! author: User! } type User { id: ID! unique email: String! unique password: String! name: String! posts: [Post!]! }为应用添加ADMIN角色在本教程的场景中User要么是拥有特殊访问权限的管理员ADMIN要么是普通客户CUSTOMER。为了区分这两类用户需要对数据模型做一处修改为User增加role字段并新增Role枚举。打开database/datamodel.graphql将User类型更新为如下形态同时补上Role枚举type User { id: ID! unique email: String! unique password: String! name: String! posts: [Post!]! role: Role! default(value: CUSTOMER) } enum Role { ADMIN CUSTOMER }注意role字段以及password字段并不会通过 GraphQL 服务器暴露给客户端因为应用 schemaapplication schema中的User类型并未包含它们。应用 schema 最终决定了哪些数据会暴露给你的客户端应用——数据模型字段与 API 暴露字段相互独立这正是 Prisma 架构中数据库层与应用层分离的体现。修改完成后需要部署数据库使变更生效。在permissions-example目录中运行yarn prisma deploy此时数据模型与 Prisma API 已更新User类型包含了role字段。定义权限需求src/schema.graphql中定义的应用 schema 暴露了以下查询与变更type Query { feed: [Post!]! drafts: [Post!]! post(id: ID!): Post! me: User } type Mutation { signup(email: String!, password: String!, name: String!): AuthPayload! login(email: String!, password: String!): AuthPayload! createDraft(title: String!, text: String!): Post! publish(id: ID!): Post! deletePost(id: ID!): Post! }本教程只关注与Post类型相关的 resolver它们的权限需求如下操作权限要求feed无权限要求。所有人包括未认证用户都可以访问已发布Post节点的feeddrafts每个用户只能访问自己的草稿即自己是该Post的authorpost只有Post的author或ADMIN用户可以使用post查询访问Post节点publish只有Post的author可以发布它deletePost只有Post节点的author或ADMIN用户可以删除它用graphql-yoga与 Prisma 实现权限规则实现权限规则的基本思路是在每个 resolver 中实现一次数据访问检查只有检查通过该操作查询、变更或订阅才会通过可用的prisma-binding被转发给 Prisma 服务。这里的检查工具是prisma-binding的exists函数。从源码层面看这个能力来自 Prisma 客户端基类的buildExists()实现见 cli/packages/prisma-client-lib/src/Client.ts客户端会遍历 schema 的 Query 类型为数据模型中的每个类型自动生成一个以类型名命名的 exists 函数调用时它内部执行对应类型的列表查询如query.posts({ where })并根据返回结果长度是否大于 0 返回布尔值private buildExists(): Exists { const queryType this._schema.getQueryType() // ... return types.reduce((acc, { type, pluralFieldName }) { const firstLetterLowercaseTypeName type[0].toLowerCase() type.slice(1) return { ...acc, [firstLetterLowercaseTypeName]: args { return thispluralFieldName.then(res { return res.length 0 }) }, } }, {}) }这意味着ctx.db.exists.Post({ ... })与ctx.db.exists.User({ ... })都是根据你的数据模型自动生成的无需手写底层查询。正如仓库中的 prisma-binding 文档所述exists是Prisma实例上的公共属性与query、mutation类似每个类型暴露一个函数接收where对象作为输入返回布尔值表示该条件是否满足。下面逐步为各 resolver 加上这些检查。feed由于所有人都能访问feed查询这里无需实现任何检查。drafts需求是每个用户只能访问自己的草稿即自己是Post的author。当前的draftsresolver 实现如下drafts(parent, args, ctx, info) { const id getUserId(ctx) const where { isPublished: false, author: { id } } return ctx.db.query.posts({ where }, info) },事实上这段代码已经满足了需求——它通过where过滤条件只检索出属于当前认证用户getUserId(ctx)从请求上下文解析出用户 id的草稿。因此这里无需任何改动。post需求是只有Post的author或ADMIN用户可以使用post查询访问Post节点。当前的实现非常直接post(parent, { id }, ctx, info) { return ctx.db.query.post({ where: { id } }, info) }但现在需要确保只有请求者是该Post的author或ADMIN用户时才返回该Post。为此我们使用prisma-binding的exists函数。将src/resolvers/Query.js中的实现更新为async post(parent, { id }, ctx, info) { const userId getUserId(ctx) const requestingUserIsAuthor await ctx.db.exists.Post({ id, author: { id: userId, }, }) const requestingUserIsAdmin await ctx.db.exists.User({ id: userId, role: ADMIN, }) if (requestingUserIsAdmin || requestingUserIsAuthor) { return ctx.db.query.post({ where: { id } }, info) } throw new Error( Invalid permissions, you must be an admin or the author of this post to retrieve it., ) }通过两次exists调用我们收集到两方面的信息发送请求的User是否确实是所请求Post的author发送请求的User是否是ADMIN。只要任一条件为真就直接返回该Post否则抛出一个权限不足的错误。publishpublish变更的需求是只有Post的author可以发布它。该 resolver 位于src/resolvers/Mutation/post.js当前实现如下async publish(parent, { id }, ctx, info) { const userId getUserId(ctx) const postExists await ctx.db.exists.Post({ id, author: { id: userId }, }) if (!postExists) { throw new Error(Post not found or youre not the author) } return ctx.db.mutation.updatePost( { where: { id }, data: { isPublished: true }, }, info, ) },当前的exists调用已经确保了请求用户是该待发布Post的author。所以这里同样不需要做任何修改需求已得到满足。deletePostdeletePost变更的需求是只有Post节点的author或ADMIN用户可以删除它。当前 resolver 位于src/resolvers/Mutation/post.js实现如下async deletePost(parent, { id }, ctx, info) { const userId getUserId(ctx) const postExists await ctx.db.exists.Post({ id, author: { id: userId }, }) if (!postExists) { throw new Error(Post not found or youre not the author) } return ctx.db.mutation.deletePost({ where: { id } }) },与publish类似exists调用已确保请求用户是待删除Post的author。但这里还需补上一种情形如果该用户是ADMINPost依然应该被删除。将src/resolvers/Mutation/post.js中的deletePost调整为async deletePost(parent, { id }, ctx, info) { const userId getUserId(ctx) const postExists await ctx.db.exists.Post({ id, author: { id: userId }, }) const requestingUserIsAdmin await ctx.db.exists.User({ id: userId, role: ADMIN, }) if (!postExists !requestingUserIsAdmin) { throw new Error(Post not found or you dont have access rights to delete it.) } return ctx.db.mutation.deletePost({ where: { id } }) },注意这里的判断逻辑只有不是作者且不是管理员时才拒绝请求二者满足其一即可删除。要点回顾观察post与deletePost的完整版实现可以看出管理员ADMIN权限在应用层的表达方式是一致的——通过ctx.db.exists.User({ id: userId, role: ADMIN })判定请求者角色。这套模式在仓库的 Authentication Authorization 迁移指南中同样被用于updatePost等场景是从 Graphcool 迁移到 Prisma 时的标准写法。测试权限可以在 GraphQL Playground 中测试这些权限规则整体流程如下在 Playground 中用signup变更创建一个新User并在 selection set 中指定token使其由服务器返回如果之前已创建过User也可以使用login变更将服务器响应中的token保存下来设置为 Playground 的Authorization请求头具体方法见下文此后所有请求都将代表该User发出。1. 创建新User首先启动服务器。在permissions-example目录下运行yarn start服务器现在运行在http://localhost:4000。在浏览器中打开该地址在app部分的defaultPlayground 中发送以下变更mutation { signup( email: sarahgraph.cool password: graphql name: Sarah ) { token } }2. 设置Authorization请求头复制返回的token将其设置为 Playground 左下角的Authorization请求头。请求头需要以 JSON 形式设置注意把__TOKEN__占位符替换为signup变更返回的认证token{ Authorization: __TOKEN__ }从现在起通过 Playground 发送的所有请求都代表刚创建的这个User。3. 验证权限规则掌握上述方法后你就可以操作可用的查询与变更验证权限规则是否生效。例如可以走一遍下面的流程以Sarah刚创建的User的身份用createDraft变更创建一个新草稿再用signup变更创建另一个User并为它获取一个token使用新用户的认证token尝试发布 Sarah 的草稿。此时应返回错误Post not found or youre not the author。如果上述流程得到预期结果说明publish的仅作者可发布规则已正确生效同理你也可以切换不同角色验证post与deletePost中作者或管理员可访问/删除的规则以及feed的完全公开访问。总结通过本教程你完成了以下完整链路使用graphql create --boilerplate node-advanced引导了一个自带认证的 GraphQL 服务器与对应的 Prisma 数据库服务通过修改数据模型并执行yarn prisma deploy为User引入了role: Role!字段与ADMIN/CUSTOMER枚举明确了五个Post相关操作的权限需求并利用prisma-binding自动生成的ctx.db.exists.*函数在 resolver 中逐个实现了数据访问检查——凡是已有检查满足需求的地方drafts、publish保持原样凡是需要补充管理员判断的地方post、deletePost追加了ctx.db.exists.User({ id, role: ADMIN })分支在 GraphQL Playground 中通过signup获取 token、设置Authorization请求头验证了跨用户越权访问会被拒绝。从源码层面看exists系列函数由 cli/packages/prisma-client-lib/src/Client.ts 中的buildExists()基于数据模型自动生成其内部通过列表查询的结果长度判断条件是否成立。这套应用层权限校验 委托转发的模式是 Prisma 架构下实现权限控制的标准实践数据模型决定数据库结构应用 schema 决定 API 暴露面resolver 中的exists检查决定谁能对哪些数据执行什么操作。赞分享后端数据库GraphQL【免费下载链接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]项目地址https://gitcode.com/gh_mirrors/pr/prisma1点击查看免费下载相关推荐基于 Prisma 与 graphql-yoga 实现 GraphQL 权限控制从数据模型到 Resolver 实战基于 Prisma 与 graphql yoga 实现 GraphQL 权限控制从数据模型到 Resolver 实战 本文是一篇面向 GraphQL 服务端开后端数据库GraphQLPrisma 与 graphql-yoga 实现 GraphQL API 权限控制从角色建模到 resolver 级访问检查Prisma 与 graphql yoga 实现 GraphQL API 权限控制从角色建模到 resolver 级访问检查 导读 本教程以 Prisma 官后端数据库GraphQL使用 Prisma 与 graphql-yoga 实现 GraphQL 权限控制从角色建模到 resolver 级访问校验使用 Prisma 与 graphql yoga 实现 GraphQL 权限控制从角色建模到 resolver 级访问校验 本文基于 Prisma 官方教程后端数据库GraphQL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

Apache Flink 内存故障排查完全指南:从 OOM 到容器被杀的全场景诊断与修复
Apache Flink 内存故障排查完全指南:从 OOM 到容器被杀的全场景诊断与修复

大数据流处理批处理数据工程 【免费下载链接】flink 项目地址: https://gitcode.com/gh_mirrors/fli/flink 点击查看 免费下载 导读 本文基于 Flink 官方内存故障排查文档(mem_trouble.md),系统梳理 Flink 进程(Task… · 2026/9/23 21:35:38

金融采购平台供应商注册失败排查:兼容性、信息匹配与材料审核
金融采购平台供应商注册失败排查:兼容性、信息匹配与材料审核

1. 项目背景:金采网是什么,为什么注册会卡住先给不熟悉的朋友交代一下背景。金采网是金融行业采购与招标信息发布和供应商管理的平台,银行、保险、证券等金融机构的采购项目大多会通过它发布招标公告,供应商需要先完成线上注册、通… · 2026/9/23 21:35:38

国际白银期货 VS 国内白银期货,交易时间差别在哪
国际白银期货 VS 国内白银期货,交易时间差别在哪

很多刚接触白银的朋友,分不清内外盘白银的交易时段,经常搞混开盘、休市时间,一不小心就踩坑。今天就把两者的时间差异一次性讲清楚。 国内沪银期货(上期所) 交易时间(北京时间): 日盘… · 2026/9/23 21:35:38

脱硫塔和洗涤塔有什么区别?六种废气处理塔一张表分清
脱硫塔和洗涤塔有什么区别?六种废气处理塔一张表分清

开篇结论:脱硫塔专治锅炉烟气SO₂,洗涤塔是通用主力;碱洗塔治酸性废气,酸洗塔治碱性废气,水洗塔洗可溶气体,喷淋塔是统称。六种废气塔分不清?一张表帮你选对。1. 六塔对比表名称原理主要处理对象… · 2026/9/23 22:20:04

旅游景点情感分析:细粒度属性级建模与BERT微调实践
旅游景点情感分析:细粒度属性级建模与BERT微调实践

简介:本资源是一套面向计算机专业本科生的毕业设计实战项目,聚焦旅游景点评论的细粒度情感分析任务,适用于Python Web开发、自然语言处理与数据库应用等课程实践或毕设选题参考。项目基于Django框架构建Web系统,集成RNCC情感分析模… · 2026/9/23 22:19:58

117 Kubernetes部署Agent服务
117 Kubernetes部署Agent服务

117 Kubernetes部署Agent服务 那晚的告警到现在还记得,新上线的采集Agent在测试集群里一会儿Running一会儿CrashLoopBackOff,kubectl logs抓出来就一行“Failed to create Kubernetes client: can’t create rest client: dial tcp: lookup kube-apiserver on 10.96.0.10:53… · 2026/9/23 22:19:58

119、Agent的配置管理与动态化
119、Agent的配置管理与动态化

119、Agent的配置管理与动态化 那晚线上告警响得人头皮发麻。一个负责代码审查的Agent,突然开始对每一行 print 都提出“请使用日志框架”的整改意见,连测试文件都不放过。我拉出日志,发现它加载的规则版本号还停留在三天前——可我明明昨天才在配置中心把这条规则下架了。… · 2026/9/23 22:19:52

118、构建可扩展的Agent基础架构
118、构建可扩展的Agent基础架构

118、构建可扩展的Agent基础架构 那天晚上十一点,线上的Agent实例突然开始集体超时,日志里刷满了TooManyRequests,但我们的API配额明明还有余量。查了一整夜,最后发现根因不在模型服务,也不在业务代码,而在我们引以为傲的“灵活”的Agent调度层——每个请求进来都会动态… · 2026/9/23 22:19:52

120、Agent的可观测性:Metrics与Tracing
120、Agent的可观测性:Metrics与Tracing

120、Agent的可观测性:Metrics与Tracing 昨天下午我盯着监控面板,发现那个Agent在凌晨开始不断重试同一个工具调用,日志里全是“timeout”,可面板上延迟曲线却是一条直线。不是不报,时候未到——因为当时只打了log,没打metrics,也没trace。后来把请求路径串起来才发现,… · 2026/9/23 22:19:46

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码