具有 Prisma 和 PropelAuth 的多租户 Next.js 应用程序
具有 Prisma 和 PropelAuth 的多租户 Next.js 应用程序
多租户应用程序
在软件世界中,一个 租户 是一起使用产品的用户的集合。这可以少至单个用户,也可以多至大型企业。
单租 是每个租户拥有自己的专用应用程序、数据库和基础设施的时候。这与 多租户 租户共享资源的地方。
在任何一种情况下,一个共同的目标是将租户彼此隔离,这样他们就无法查看或修改彼此的数据。在单租户模型中,这很自然地发生,因为它们是完全分离的。在多租户模型中,这必须在应用程序或数据库级别强制执行。
即使有这么多的工作,为什么还要选择多租户应用程序?有一些明显的优势,比如不需要为每个客户维护或支付单独的基础设施。在这篇文章中,我们将展示如何使用 Next.js、Prisma 和 PropelAuth 构建多租户应用程序。
我们要建造什么?
我们将构建一个简单的 B2B 应用程序,每个用户都可以在租户内发布“帖子”。租户中的所有用户都应该能够阅读他们自己的帖子,并且租户之外的任何人都应该能够查看或访问它们。
在我们的 B2B 产品中,我们的租户是 组织 ,我们稍后会看到更多。最终产品将如下所示:
租户中的每个人都可以查看和发布只有他们可以看到的帖子。
我们如何处理多个租户中的用户?
如果用户只在一个租户中,那么我们应该显示哪个租户的数据非常明显。但是当用户在多个租户中时会发生什么?
在实践中,这个问题经常出现。 GitHub 允许用户同时在多个组织中。同样,您可以在任意数量的 Slack 工作区中使用,并且您可以拥有多个在其间切换的 Google/Twitter 帐户。
你如何解决这个问题取决于你的应用程序,但有几个思想流派:
- 每个租户都应该有自己唯一的 URL(例如 https://tenant.example.com 或者 https://example.com/tenant/ )
- 只有一个网址(例如 https://app.example.com ) 并且用户使用下拉菜单或类似的东西选择要在 UI 中查看的租户。
有关您选择哪种方法的更多详细信息,我们已经写了每种方法的优缺点 这里 .在此示例中,我们假设用户可以通过转到其租户名称在路径中的 URL 来查看其租户的帖子,例如 https://example.com/tenant/
在 Next.js 中检查路径参数
首先,我们将创建一个 React 钩子,它可以通过检查 URL 的路径来告诉我们用户当前正在查看哪个租户。首先创建一个新的 Next.js 应用程序
Next.js 支持 动态路线 这使得这非常简单。一个文件创建于 pages/org/[orgName]/posts.tsx
将响应任何路线,例如 /org/某事/帖子
或者 /org/somethingelse/posts
.
如果我们在该文件中编写以下代码:
我们将能够根据用户的 URL 查看用户正在尝试查看的租户
验证用户是否在给定租户中
我们目前没有用户的概念,更不用说租户了。我们不希望任何人都能够查看“123”组织或任何组织的所有帖子。
这是哪里 PropelAuth PropelAuth 是为多租户和 B2B 用例设计的身份验证服务。它包括供每个租户/组织自行管理的自助服务 UI。我们的用户将能够注册、创建租户并邀请他们的同事,而无需我们为其编写任何代码。
这 入门指南 将引导您了解如何配置用户的身份验证体验,从 UI 的外观到您为用户提供的登录选项,再到这些用户的组织选项。这个 演示 显示了一些可用的配置选项。
配置完成后,我们的用户现在可以自行注册、登录、创建租户等。我们所要做的就是检查他们是否在他们试图访问的租户中。我们可以做到这一点 PropelAuth 的 React 库 .
那么,在 页面/_app.ts
,我们用 AuthProvider 包装我们的应用程序。 AuthProvider 会联系我们的 PropelAuth 实例并获取我们当前用户的元数据(如果他们已登录)。您将需要您的 授权网址 您可以在前端集成下的仪表板中找到它。
就是这样,我们现在可以在应用程序的任何地方访问我们的用户信息。我们可以使用高阶函数,例如[ withAuthInfo](https://docs.propelauth.com/reference/frontend-apis/react/#withauthinfo)
或钩子之类的[ 使用AuthInfo](https://docs.propelauth.com/reference/frontend-apis/react/#useauthinfo)
.让我们更新我们的 /org/[orgName]/posts.tsx
文件以检查用户是否在 orgName 中。
对于我们的用户不是其成员的任何租户/组织,他们将收到“未找到”错误。
请注意,这只是前端检查。前端检查很重要 可用性 但不是 安全 .如果我们为一个租户获取所有帖子,然后决定不在前端显示它,那么任何用户都可以检查他们的网络流量来查看数据。
我们仍然希望对此进行检查,以便为出现在错误页面上的用户提供合理的错误消息,但现在让我们看看如何制作 认证 对我们后端的请求。
向我们的后端发出经过身份验证的请求
为了制作一个 认证 请求,我们需要为我们的后端提供一些 可验证的 证明我们的用户就是他们所说的人的信息。 PropelAuth 提供 访问令牌 为此,我们的后端可以在不发出任何外部请求的情况下进行验证。我们已经从 useOrgMembershipByPathParam 所以让我们使用它。
当我们的 orgMembership 更改并呈现页面时,我们基本上调用 fetchPosts。为简洁起见,我们将省略帖子本身的样式。至于 fetchPosts 方法本身:
由于我们的后端 API 不是面向客户的,因此我们可以根据需要传入 orgId。正如我们上面所做的那样,我们可以使用查询参数,继续使用路径参数,将其放在发布请求的正文中,等等。
保存帖子非常相似,我们只需要一个用于文本本身的基本文本区域,然后我们将使用以下函数来保存帖子:
我们现在在前端拥有了我们需要的一切——唯一的问题是我们还没有后端。让我们使用 Next.js 的内置 API 路由来解决这个问题。
使用 Next.js API 路由和 Prisma 创建我们的后端
如果没有某种方式将帖子存储在某个地方,我们的后端将不会很有用。我们将设置 Prisma,一种流行的 TypeScript ORM,它将管理我们所有的数据库操作,包括迁移。
之后,你的 repo 中应该有一个新文件, 棱镜/schema.prisma
这是我们将定义我们的模式的地方。架构本身相当简单。我们想要一个包含一些要显示的文本的帖子。帖子应与租户(组织)和用户相关联。
没什么太花哨的,每个帖子都有一个默认为新 UUID 的 post_id。它包含租户 (org_id) 和用户 (user_id) 的 ID。最后,它包含我们的文本。现在我们可以迁移我们的数据库,这意味着创建或更新它到最新的模式:
将来,如果我们想添加更多字段,例如时间戳,我们可以更新我们的模式,然后 migrate 会处理剩下的事情。
使用 Next.js API 路由
Next.js API 路由允许您在 Next.js 中创建自己的 API。正如 Next.js 自己所说:
文件夹内的任何文件 页面/api
映射到 /api/*
并将被视为 API 端点而不是 页
.它们是仅限服务器端的捆绑包,不会增加您的客户端捆绑包大小。
创建一个新文件 页面/api/post.ts
它将响应请求 /api/发布
我们需要检查 方法
首先决定如何处理请求:
我们将通过列出组织/租户的所有帖子来响应 GET 请求,就像前端期望的那样:
你可能会注意到 邮政 进口自 @prisma/客户 是我们的 Post 类型,包括 post_id、org_id、user_id 和 text。
但是有几个问题,首先,我们如何知道我们应该为哪个租户/组织获取帖子?此外,我们如何知道发出 API 请求的人是否在该租户中?
早些时候,我们从前端传递了两条信息:
- org_id 作为查询参数
- 访问令牌是 可验证的 通过我们的后端
PropelAuth 除了提供前端库外,还提供后端库来验证这些令牌。我们将按照 Next.js API 路由入门指南 ,这让我们使用 @propelauth/快递
图书馆:
通过使用仪表板中提供给我们的参数调用 initAuth 来设置我们的后端:
最后,我们将调用 要求组织成员 ,这将确保提供了有效的访问令牌并且用户在指定的组织中。综上所述,我们的 getHandler 应该如下所示:
我们将通过创建一个新帖子并使用相同的函数来响应 POST 请求:
在编写此函数时,您可能会注意到 Prisma 的最佳功能之一——您可以在此处获得自动完成和类型安全:
就这样!我们现在拥有测试产品所需的一切。
测试
我们先测试一下,我们不能查看其他租户的数据。如果我们前往任意租户的帖子页面,我们将看到“未找到”消息。
但是,就像我们之前说的,这只是一个前端检查。让我们使用 cURL 来确保我们不能直接向后端发出请求:
正如预期的那样,我们得到一个 401,因为我们没有指定一个访问令牌来表示我们是一个有效的用户。如果我们确实传递了一个有效的访问令牌,但仍然传递了一个 org_id 如果我们不在,我们将收到 403,表示我们无权查看该组织的数据。
最后,我们可以在 PropelAuth 提供的托管 UI 中创建一个组织:
发表帖子并验证我们是否可以查看它:
概括
我们已经构建了多租户 B2B 应用程序所需的大部分构建块。我们的用户可以自己注册、创建租户和管理租户。我们的后端由高度可扩展的 Next.js API 路由提供支持。借助 Prisma,我们在应用程序和数据库之间实现了数据库迁移和类型安全。
更多内容在 ** 纯英语.io** .注册我们的 ** 免费每周通讯** .跟着我们 ** 推特** , ** 领英** ** , ** YouTube** ** , 和 __不和谐 ** .** 对增长黑客感兴趣?查看 ** 电路** ** .**
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明