与 Supabase 集成
学习如何将 Logto 与 Supabase 集成,以提升你应用程序的身份验证体验。
Logto 是一家现代化的身份认证服务提供商,能够为应用程序提供安全、全面且用户友好的登录支持。它还提供了大量的 SDK 和多个框架及编程语言的集成指南,使你能够在几分钟内将企业级身份认证服务无缝集成到你的应用程序中。
本文主要详细介绍了如何将 Supabase 与 Logto 集成。
Supabase 基础知识
Supabase 利用 Postgres的行级安全性来控制数据访问权限。简单来说,通过为数据库中的表创建行级安全性策略,我们可以限制和管理谁可以读取、写入和更新表中的数据。
假设你的数据库中有一个名为 "posts" 的表,内容如下:
表中的 user_id
字段表示每条帖子数据所属的用户。你可以基于 user_id
字段限制每个用户访问自己的帖子数据。
然而,在实现这一点之前,Supabase 需要能够识别正在访问数据库的当前用户。
向 Supabase 请求中添加用户数据
得益于 Supabase 对 JWT 的支持,当我们的应用程序与 Supabase 交互时,我们可以利用由 Supabase 提供的 JWT 密钥生成一个包含用户数据的 JWT,然后将此 JWT 作为 Authorization 请求头发送。在接收到请求时,Supabase 会自动验证 JWT 的有效性,并允许在后续流程中访问其中包含的数 据。
首先,我们可以在 Supabase 仪表盘中的 "Project Settings" 获取 Supabase 提供的 JWT 密钥:
接下来的步骤中,当我们使用 Supabase SDK 向 Supabase 发出请求时,我们会使用此密钥生成 JWT,并将其作为 Authentication 请求头附加到请求中。 (请注意,此过程发生在你应用程序的后端服务中,JWT 密钥不应暴露给第三方)。
接下来,进入 Supabase 仪表盘中的 SQL 编辑器,创建一个用于提取请求中携带的 userId 的函数:
图中使用的代码如下:
如代码所示,在 Supabase 中,你可以通过调用 request.jwt.claims
来提取我们生成的 JWT 的有效负载。有效负载内的 userId
字段就是我们设置的值。
通过此函数,Supabase 就可以确定当前访问数据库的用户。
创建行级安全性策略
接下来,我们可以根据 posts 表中的 user_id
字段创建行级安全性策略,以限制每个用户仅访问自己的帖子数据。
- 进入 Supabase 仪表盘中的 Table Editor 页面,选择 posts 表。
- 点击表顶部的 "Add RLS Policy" 按钮。
- 在弹出的窗口中点击 "Create policy"。
- 输入策略名称并选择 SELECT Policy 命令。
- 在下面代码的
using
块里输入:
通过这种方式,可以在 Supabase 中实现数据访问控制。
在真实的应用程序中,你还可能会创建各种策略来限制用户的操作,如数据插入和修改。然而,这超出了本文的讨论范围。有关于行级安全性 (RLS) 的更多信息,请参阅 使用 Postgres 行级安全性保护你的数据。
Logto 的基本集成过程
如前所述,由于 Supabase 使用了 RLS 进行访问控制,因此与 Logto(或任何其他身份认证服务)集成的关键在于获取授权用户的 user id,并将其发送给 Supabase。整个过程如下示意图所示:
接下来,我们将基于此过程图解释如何将 Logto 与 Supabase 集成。
Logto 集成
Logto 提供了多个框架和编程语言的集成指南。
一般来说,使用这些框架和语言构建的应用程序可以分为原生应用、单页应用 (SPA)、传统 Web 应用和 M2M(机器对机器)应用。你可以访问 Logto 快速入门 页面,根据你使用的技术栈将 Logto 集成到你的应用程序中。随后,根据应用程序类型,按照下列说明将 Logto 集成到你的项目中。
原生应用或 SPA
原生应用和 SPA 都在你的设备上运行,登录后获取的凭证(访问令牌)存储在你的设备上。
因此,当你的应用程序与 Supabase 进行集成时,需要通过后端服务与 Supabase 进行交互,因为不能将敏感信息(如 Supabase JWT 密钥)暴露在每个用户的设备上。
假设你正在使用 React 和 Express 构建你的 SPA。你已按 Logto React SDK 指南 成功集成 Logto 到你的应用程序中(你可以参考我们 react 示例 中的代码)。另外,你已按 使用 Node (Express) 保护你的 API 文档在后台服务器上添加了 Logto 访问令牌验证。
接下来,你将使用从 Logto 获取的访问令牌来向后台服务器请求用户数据:
在后台服务器中,你已经通过中间件从访问令牌中提取了已登录用户的 id:
现在,你可以使用上面描述的 getSupabaseClient
将 userId
附加到用于后续向 Supabase 发送请求的 JWT 中。或者,你也可以创建一个中间件,为需要与 Supabase 交互的请求创建一个 Supabase 客户端:
在随后的处理流程中,你可以直接调用 ctx.supabase
与 Supabase 交互:
在此代码中,Supabase 将基于之前设置的策略仅返回属于当前用户的帖子数据。
传统 Web 应用
传统 Web 应用与原生应用或 SPA 的主要区别在于传统 Web 应用仅在 Web 服务器上渲染和更新页面。因此,用户凭证由 Web 服务器直接管理,而在原生应用和 SPA 中,凭证存储在用户设备上。
当将 Logto 与 Supabase 中的传统 Web 应用集成时,你可以直接从后端获取已登录用户的 id。
以 Next.js 项目为例,在你根据 Next.js SDK 指南 将 Logto 集成到项目中之后,你可以使用 Logto SDK 提取用户信息并构建与 Supabase 交互所需的 JWT。
机器对机器应用
机器对机器(M2M)通常用于你的应用程序需要直接与资源服务器通信的情况,例如一个静态服务每日拉取帖子等。
你可以参考 机器对机器:使用 Logto 进行身份认证 指南来进行机器对机器应用认证。Supabase 与机器对机器应用的集成类似于原生应用和 SPA(详见 "原生应用或单页应用" 部分 ),需要从 Logto 获取访问令牌,然后通过受保护的后台 API 验证它。
但需要注意的是,原生应用和 SPA 通常为最终用户设计,因此获取的用户 id 代表的是用户本身,而机器对机器应用的访问令牌代表的是应用程序本身,访问令牌负载中的 sub
字段是 M2M 应用的客户端 id 而不是特定用户。因此,在开发过程中,需要区分哪些数据是针对 M2M 应用的。
此外,如果你希望特定的 M2M 应用代表整个服务访问 Supabase 以绕过 RLS 限制,可以使用 Supabase 的 service_role
密钥创建一个 Supabase 客户端。当你希望执行需要访问所有数据的管理或自动化任务,而不受为个人用户设置的行级安全性策略限制时,这非常有用。
你可以在与 JWT 密钥相同的页面上找到 service_role
密钥:
创建 Supabase 客户端时使用 service_role
密钥,该客户端将能够访问数据库中的所有数据:
总结
在本文中,我们深入探讨了 Logto 与 Supabase 的集成,重点讲解了关键的集成点和关键技术。我们探索了 JWT 验证和行级安全性策略等概念,并指导你如何将 Logto 无缝集成到你的 Supabase 驱动的应用程序中。希望通过这些知识,能让你自信地提升应用程序的安全性、功能性,甚至通过附加特性扩展你的项目。