Graphcool 迁移至 Prisma 实战Authentication 与 Authorization 架构升级指南【免费下载链接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]项目地址: https://gitcode.com/gh_mirrors/pr/prisma1本篇指南基于 Prisma 开源仓库gh_mirrors/pr/prisma1中的官方升级文档系统讲解如何将 Graphcool Framework 的注册/登录Authentication与权限规则Authorization迁移到 Prisma 的应用层架构中。你将学会把基于 resolver 与 permission query 的旧鉴权体系重构为基于 JWT prisma-binding/Prisma Client 的新体系并在graphql-yoga服务器中落地 signup/login resolver 与基于exists函数的权限检查最终完成从框架内置鉴权到应用层自治鉴权的完整范式切换。迁移背景Graphcool 与 Prisma 的鉴权哲学差异在深入迁移步骤之前有必要先理解两个平台在鉴权设计上的根本分歧这正是整个升级工作的出发点。Graphcool Framework 的旧鉴权模型在 Graphcool Framework 时代认证Authentication是通过 resolver 函数schema extension实现的。其工作链路包含三个固定步骤定义 resolver在 GraphQL schema 中以Mutation类型扩展的形式声明 signup 与 login 的 resolver 函数提供实现直接在 Graphcool Framework 中用 JavaScript 提供 resolver 实现或通过 webhook 调用自托管函数连接二者通过调整服务定义文件service definition file把 mutation 定义与实现绑定起来。与此同时数据访问的安全由permission queries权限查询概念支撑——API 上的每个操作都可以关联一条或多条权限规则操作执行前会先校验这些规则。这种认证 权限耦合进框架的模式导致 Graphcool 服务同时承担了业务逻辑与安全逻辑的双重职责。Prisma 的新鉴权模型Prisma 采用了完全不同的理念官方升级文档明确指出Prisma 提供的是一个基于 token可理解为 API Key的简单系统用于访问 Prisma API而非像 Graphcool 那样把认证绑定到权限系统上。这带来两个关键变化用户认证与权限规则下沉到应用层由你的 GraphQL 服务器例如graphql-yoga自己实现JWT 令牌由你自行生成不再由graphcool-lib代为签发。这一设计的直接收益是更清晰的架构与更好的关注点分离separation of concernPrisma 只负责数据层的存取鉴权逻辑完全由业务应用掌控。前提与准备官方指南假定你正在使用以下技术栈请确认你的环境与之匹配graphql-yoga作为 GraphQL 服务器schema 以 SDLSchema Definition Language编写数据模型已迁移至 Prisma 服务模型定义见下文 Step 3。Step 1迁移 Schema 定义Graphcool 时代的 schema extension在 Graphcool Framework 服务中你通常会有如下形式的 schema extension通过signupUser与authenticateUser两个 mutation 提供注册与登录能力返回的token是graphcool-lib生成的 JWT客户端需将其放入AuthorizationHTTP 头来认证请求type Mutation { signupUser(email: String!, password: String!): SignupUserPayload authenticateUser(email: String!, password: String!): AuthenticateUserPayload } type SignupUserPayload{ userId: ID! token: String! } type AuthenticateUserPayload { token: String! }迁移到 graphql-yoga 后的新定义这些定义可以整体搬入graphql-yoga服务器的 schema 中。官方文档特别提醒迁移过程中你可以去掉一个历史 workaround——旧框架下 resolver 函数无法返回模型类型model types因此不得不定义独立的SignupUserPayload/AuthenticateUserPayload包装类型现在直接返回User即可。官方建议的新定义如下type Mutation { signup(email: String!, password: String!): AuthPayload login(email: String!, password: String!): AuthPayload } type AuthPayload { token: String! user: User! }注意两个细节变化authenticateUser更名为更常见的login且AuthPayload直接携带user: User!字段签名更简洁、对客户端更友好。Step 2迁移 Resolver 函数接下来需要在应用层实现signup与login的 resolver。核心职责是在 resolver 内自行生成 JWT并返回给用户在signupresolver 中同时创建User类型的新节点。官方文档给出了auth.js的参考实现请先安装bcryptjs与jsonwebtoken依赖const bcrypt require(bcryptjs) const jwt require(jsonwebtoken) const auth { async signup(parent, args, ctx, info) { const password await bcrypt.hash(args.password, 10) const user await ctx.db.mutation.createUser({ data: { ...args, password }, }) return { token: jwt.sign({ userId: user.id }, process.env.JWT_SECRET), user, } }, async login(parent, { email, password }, ctx, info) { const user await ctx.db.query.user({ where: { email } }) if (!user) { throw new Error(No such user found for email: ${email}) } const valid await bcrypt.compare(password, user.password) if (!valid) { throw new Error(Invalid password) } return { token: jwt.sign({ userId: user.id }, process.env.JWT_SECRET), user, } }, } module.exports { auth }逐段解读其中的关键实现细节密码哈希bcrypt.hash(args.password, 10)使用 10 个 salt rounds 对明文密码加盐哈希绝不允许明文入库创建用户ctx.db.mutation.createUser({ data: { ...args, password } })将原始参数与哈希后的密码一并写入这里的ctx.db正是 Prisma Client或prisma-binding的Prisma实例JWT 签发jwt.sign({ userId: user.id }, process.env.JWT_SECRET)在服务端用自己的密钥建议通过环境变量注入签名令牌payload 中只需携带userId登录校验先按email查出用户并判空再用bcrypt.compare校验密码两者任一失败都抛出明确错误避免泄露用户是否存在这类信息。AuthPayload 的字段解析由于signup直接返回了user对象通常无需额外 resolver。但官方文档仍给出了AuthPayload.js的示例展示如何在需要时按 id 二次查询完整用户const AuthPayload { user: async ({ user: { id } }, args, ctx, info) { return ctx.db.query.user({ where: { id } }, info) }, } module.exports { AuthPayload }这里user作为AuthPayload的字段 resolver 被单独拆分它从父级 payload 解构出user.id再委托给ctx.db.query.user并透传infoselection set确保按客户端实际请求的字段返回。Step 3迁移权限规则Permission Rules权限查询到exists的映射官方指南的核心结论是prisma-binding包中的exists函数是迁移权限查询permission queries的首选工具它扮演了与 Graphcool 中权限查询相似的角色。先看官方文档给出的 Prisma 数据模型示例type User model { id: ID! unique name: String! posts: [Post!]! } type Post model { id: ID! unique title: String! author: User! }在 Graphcool Framework 中若要表达只有Post的作者才能更新它需要把下面的 permission query 关联到updatePostmutation 上query ($user_id: ID!, $post_id: ID!) { SomePostExists(filter: { id: $post_id author: { id: $user_id } }) }在 Prisma 架构下这一条件检查被搬进了应用层updatePostresolver 中用ctx.db.exists.Post(...)表达完全相同的语义async function updatePost(parent, { id, title, text }, ctx, info) { // getUserId throws an error if the requesting user is not authenticated const userId getUserId(ctx) // this expresses the same condition as the permission query above const requestingUserIsAuthor await ctx.db.exists.Post({ id, author: { id: userId, }, }) // only if the condition is true, the post is actually updated if (requestingUserIsAuthor) { return await ctx.db.mutation.updatePost({ where: { id }, data: { title, text }, }, info) } throw new Error( Invalid permissions, you must be an admin or the author of a post to update it, ) }这一段的迁移模式具有普遍性可归纳为三步鉴权getUserId(ctx)先从请求中解析出当前用户未认证则直接抛错授权判定ctx.db.exists.Post({ id, author: { id: userId } })以布尔值表达该 Post 是否存在且作者为当前用户条件执行仅当条件成立才真正调用updatePostmutation否则抛出权限错误。关于权限规则的更多实现细节官方文档指引参考 this tutorial。exists的底层实现原理exists并不是黑魔法——从源码中可以确认其底层机制。在 cli/packages/prisma-client-lib/src/Client.ts 中buildExists()方法遍历 schema 的查询类型为每个模型类型生成形如exists.Post(args)的函数。每个函数的实现是先以where条件查询对应的列表字段再检查结果长度是否大于 0最终返回布尔值private buildExists(): Exists { const queryType this._schema.getQueryType() if (!queryType) { return {} } if (queryType) { const types getTypesAndWhere(queryType) 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 }) }, } }, {}) } return {} }也就是说exists.Post({ id, author: { id: userId } })在底层等价于一次posts(where: {...})列表查询通过结果非空来判断节点是否存在。这解释了为什么exists能无缝承接 Graphcool permission query 的过滤语义——两者都是基于where条件的谓词判断。JWT 解析与getUserId辅助函数官方文档同时给出了getUserId的标准实现它负责从 HTTP 请求头中提取并校验 JWTfunction getUserId(ctx) { const Authorization ctx.request.get(Authorization) if (Authorization) { const token Authorization.replace(Bearer , ) const { userId } jwt.verify(token, process.env.APP_SECRET) return userId } throw new AuthError() } class AuthError extends Error { constructor() { super(Not authorized) } }其工作流程为读取请求头中的Authorization字段形如Bearer token→ 剥掉Bearer前缀得到原始 JWT → 用jwt.verify校验签名并解出userId若请求头缺失或令牌无效则抛出AuthError。令牌的传输与服务端处理迁移完成后客户端与服务端之间形成如下鉴权闭环客户端注册/登录调用signup/loginmutation服务端返回{ token, user }客户端携带令牌后续请求在 HTTP 头中携带Authorization: Bearer jwt服务端校验应用层 resolver 通过getUserId(ctx)解析出当前用户身份授权决策结合ctx.db.exists与业务逻辑决定是否放行。在 Prisma 服务这一侧prisma-binding的Prisma客户端在实例化时若配置了secret会自动用该 secret 签发 token 并在每次请求中附带Authorization: Bearer token头。相关逻辑同样位于 cli/packages/prisma-client-lib/src/Client.ts构造函数中const token secret ? sign({}, secret!) : undefined随后在BatchedGraphQLClient的请求头与 WebSocket 订阅的connectionParams中统一注入。这说明应用层的 JWT 与应用访问 Prisma API 的服务级 token 是两套并行的凭证体系——前者代表用户后者代表服务。常见注意事项环境变量JWT_SECRET/APP_SECRET应通过环境变量注入切勿硬编码进源码或提交到版本库密钥一致性签发jwt.sign与校验jwt.verify必须使用同一密钥否则getUserId会因签名不匹配而持续抛错密码安全始终使用bcryptjs等加盐哈希登录比对用bcrypt.compare不要自行实现哈希或明文存储权限检查的位置Prisma 不再替你做业务级授权任何敏感 mutation/query 都必须在应用层 resolver 中显式完成身份确认与权限判定exists的语义exists返回布尔值适合作为前置条件判断但不提供返回数据的能力需要数据时仍应走ctx.db.query/ctx.db.mutation。迁移前后对比小结维度Graphcool FrameworkPrisma迁移后认证实现位置resolver 函数schema extension应用层 resolvergraphql-yogaJWT 生成graphcool-lib代为生成应用层用jsonwebtoken自行生成权限规则permission query 关联 API 操作应用层ctx.db.exists条件判断返回类型限制resolver 不能返回模型类型需包装 payload可直接返回User等模型类型职责划分认证与权限耦合进框架关注点分离Prisma 专注数据层完成上述三个 Step 后你的服务将从框架内置鉴权平滑过渡到应用层自治鉴权同时获得更简洁的 schema、更灵活的权限控制与更清晰的架构边界。官方文档还提供了完整的实践示例auth 与 permissions 两个示例工程可结合 Prisma Bindings API 参考 与 客户端源码实现 进一步深入验证迁移效果。【免费下载链接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]项目地址: https://gitcode.com/gh_mirrors/pr/prisma1创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
低空无人机消防AI识别系统:架构、模型与边缘部署实践 简介:《低空无人机消防AI识别系统设计方案》是一份面向消防应急、无人机与AI视觉融合领域的PPT方案资源,适合方案设计人员、消防科技研发者及项目申报者参考。方案针对传统消防作业时效性差、火情发现滞后、人工巡查效率低、指挥调度效率低等痛点&#x… · 2026/9/23 15:37:42
wired-link 手绘风格链接组件:使用指南与源码实现解析 UI组件前端 【免费下载链接】wired-elements Collection of custom elements that appear hand drawn. Great for wireframes or a fun look. 项目地址: https://gitcode.com/gh_mirrors/wi/wired-elements 点击查看 免费下载 wired-link 是 wired-elements 组件库… · 2026/9/23 15:37:41
移相全桥ZVS变换器深度解析:开关模态、倍流整流与UCC3895设计 简介:面向开关电源设计人员、电力电子工程师及电气工程相关专业学生的这份PDF文档,系统介绍一种采用电流模式移相PWM控制的高频DC/DC变换器,重点阐述在宽负载范围内实现开关器件零电压软开关(ZVS)的电路结构与工作过程… · 2026/9/23 15:37:35
IEC 60079-11:2023本质安全回路参数计算与4-20mA系统设计要点 简介:IEC 60079-11:2023 是国际电工委员会发布的爆炸性环境用电气设备本质安全型“i”保护标准,对应第7版最新文本。资源面向防爆电气设计、制造、检测认证工程师及石化、煤矿等易燃易爆场所运维人员,旨在解决本安设备的设计、评估与合规判定… · 2026/9/23 16:24:58
杭州校招高频面试题避坑指南:版本升级后API全变了怎么办 杭州校招高频面试题避坑指南:版本升级后API全变了怎么办 版本升级后 API 全变了,这是杭州校招现场最让人头疼的“高频面试题”陷阱。很多候选人拿着旧版文档去面试,结果被面试官一句“现在都用 v3… · 2026/9/23 16:24:52
从数据管理到语义治理,业务智能盘点平台v2.0试图补齐中台短板 中翰软件近日发布中翰业务智能盘点平台v2.0,基于自研Navigate OS底座和业务梳理平台v1.0。该平台定位为“让业务人员自己就能把业务理清楚”的一站式智能盘点与知识构建平台,融合AI智能解析能力与FDE式业务梳理方法论,实现指标梳理、资源盘点… · 2026/9/23 16:24:52
git-cliff 模板语法完全指南:基于 Tera 的 Changelog 模板引擎与自定义过滤器实战 git-cliff 模板语法完全指南:基于 Tera 的 Changelog 模板引擎与自定义过滤器实战 【免费下载链接】git-cliff A highly customizable Changelog Generator that follows Conventional Commit specifications ⛰️ 项目地址: https://gitcode.com/gh_mirrors/gi/… · 2026/9/23 16:24:51
搞懂分辨率是什么的保姆级教程,解决API变动痛点 搞懂分辨率是什么的保姆级教程,解决API变动痛点 版本升级后 API 全变了,导致项目渲染错乱?别慌,这篇关于 分辨率是什么 的保姆级教程,能帮你从源码底层彻底搞清 DPR 机制。… · 2026/9/23 16:24:51
3个实战项目揭秘:在家可开啥小型加工厂避坑指南 3个实战项目揭秘:在家可开啥小型加工厂避坑指南 复制来的代码跑不通,报错信息满屏红,改了一下午还是没头绪。这种崩溃感,每个写代码的人都懂。尤其是在做 实战项目… · 2026/9/23 16:24:39
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29