新闻详情

新闻详情

首页 / 资讯中心 / 详情

Graphcool 迁移至 Prisma 实战:Authentication 与 Authorization 架构升级指南

发布时间:2026/11/12 16:00:20来源:尧图网络
Graphcool 迁移至 Prisma 实战:Authentication 与 Authorization 架构升级指南
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),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

【外设】之大彩串口显示屏 2026/11/11 13:52:51

【外设】之大彩串口显示屏

大彩串口屏初步使用 1 .官网下载 STM32 屏幕 GUI 设计资料 http://www.gz-dc.com/category/typeid/4112 找到 STM32 Keil 工程,移植相关代码因项目而异进行移植,由于项目简单,本人只对用到的指令接口进行修改。 比如:注意事项&…

阅读更多 →
无法下载Windows系统iso文件 2026/11/10 19:42:40

无法下载Windows系统iso文件

当我遇到这个问题的时候,我打开了一个网站: 登录 然后我打算下载的时候: 突然那个官方的连接就可以下载了:

阅读更多 →
【清华代码熊】DeepSeek V4.1 Flash 后训练详解 2026/11/12 9:50:02

【清华代码熊】DeepSeek V4.1 Flash 后训练详解

📌 上期解析了 DeepSeek V4.1 Flash 模型架构改进,本期解析 DeepSeek V4.1 Flash 预训练/后训练技术: 🌟 预训练:45T 文本 多模态混合语料、直接训练 sparse attention(取消 DeepSeek V4 的 dense 冷启动&…

阅读更多 →
Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ... 2026/11/12 9:25:38

Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ...

文章主要内容和创新点 主要内容 本文聚焦于多模态大语言模型(MLLM)强化学习(RL)训练中的效率问题,提出了一个名为Shuffle-R1的框架。研究发现,当前RL训练存在两个关键缺陷: 优势值坍缩(Advantage Collapsing):批次中大多数优势值集中在零附近,导致有效梯度信号被淹…

阅读更多 →
PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction 2026/11/12 15:57:44

PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction

一、文章主要内容总结 本文聚焦于利用大型语言模型(LLMs)实现个人身份信息(PII)脱敏的研究,旨在解决传统脱敏方法(如基于规则的系统、领域特定命名实体识别(NER)模型)泛化能力差、跨格式/跨语境适应性弱的问题。 研究通过全面评估多种LLM架构(包括密集型LLM(D-LLM…

阅读更多 →
LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model 2026/11/10 17:14:10

LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model

文章主要内容和创新点 主要内容 本文聚焦于二进制图像-文本相关性评估任务(判断图像与文本“相关”或“不相关”),针对该任务中文本格式多样、相关性定义随场景变化等挑战,提出了基于多模态大语言模型(MLLM)的解决方案LLaVA-RE。 模型设计:LLaVA-RE基于LLaVA 1.5架构,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉