2022年1月28日
使用 TypeScript、PostgreSQL、Next.js、Prisma 和 GraphQL 构建的全栈应用:身份验证
本文是构建使用 Next.js、GraphQL、TypeScript、Prisma 和 PostgreSQL 全栈应用的课程的第三部分。在本文中,您将学习如何为您的应用添加身份验证。
目录
介绍
在本课程中,您将学习如何构建 'awesome-links',一个全栈应用,用户可以在其中浏览精选链接列表并收藏他们喜欢的链接。
在第 2 部分中,您使用 GraphQL Yoga 和 Pothos 构建了 GraphQL API。然后,您在前端使用 Apollo Client 来消费 GraphQL API。
开发环境
要跟随本教程,请确保您已安装 Node.js 和 GraphQL 扩展。您还需要运行 PostgreSQL 数据库。
如果您是从第 2 部分开始学习,则可以跳过项目设置并直接进入使用 Auth0 进行身份验证和保护 GraphQL API 部分。
注意:您可以在本地设置 PostgreSQL,或者在 Heroku 上设置托管实例。在本课程结束时的部署步骤中,您将需要一个远程数据库。
克隆仓库
您可以在 GitHub 上找到本课程的完整源代码。
注意:每篇文章都有一个对应的分支。这样,您可以在阅读时跟随学习。通过检出 part-3 分支,您将拥有与本文相同的起点。每个分支之间可能存在一些差异,因此为了避免遇到任何问题,建议您克隆本文的分支。
要开始,请导航到您选择的目录并运行以下命令来克隆仓库
导航到克隆的应用并安装依赖项
种子数据库
在设置 PostgreSQL 数据库之后,将 env.example
文件重命名为 .env
并设置数据库的连接字符串。之后,运行以下命令在数据库中创建表
有关连接字符串格式的更多详细信息,请参阅第 1 部分 – 将 Prisma 添加到您的项目。
如果 prisma migrate dev
没有触发种子步骤,请运行以下命令来种子数据库
此命令将运行 /prisma
目录中的 seed.ts
文件。seed.ts
使用 Prisma Client 在您的数据库中创建四个链接和一个用户。
您现在可以通过运行以下命令启动应用程序服务器
项目结构和依赖项
项目具有以下文件夹结构
这是一个 Next.js 应用程序,它使用以下库和工具
- Prisma 用于数据库访问/CRUD 操作
- Next.js 作为全栈 React 框架
- TailwindCSS 用于样式设置
- Pothos 作为 GraphQL 模式构建库
- GraphQL Yoga 作为 GraphQL 服务器
- Apollo Client 作为 GraphQL 客户端
pages 目录包含以下文件
index.tsx
:从 API 获取链接并在页面上显示它们。结果是分页的,您可以获取更多链接。_app.tsx
:根组件,允许您在页面之间导航时持久化布局和状态。/api/graphql.ts
:使用 Next.js 的 API 路由的 GraphQL 端点。
使用 Auth0 进行身份验证和保护 GraphQL API
配置 Auth0
为了保护应用,您将使用 Auth0 – 一种开箱即用的身份验证和授权解决方案。
创建 帐户后,导航到位于左侧边栏的 Applications 下拉菜单,然后从子菜单中选择 Applications。
接下来,单击 + Create application 按钮创建一个新应用。为您的应用命名,选择 Regular Web Application,然后通过选择对话框右下角的 Create 按钮完成应用的创建。
成功创建应用后,导航到 Settings 选项卡并将以下信息复制到您项目的 .env
文件中
- 域名
- 客户端 ID
- 客户端密钥
AUTH0_SECRET
:用于加密会话 Cookie 的长密钥值。您可以通过在终端中运行openssl rand -hex 32
来生成合适的字符串。AUTH0_BASE_URL
:您的应用程序的基本 URL。AUTH0_ISSUER_BASE_URL
:您的 Auth0 租户域的 URL。AUTH0_CLIENT_ID
:您的 Auth0 应用程序的客户端 ID。AUTH0_CLIENT_SECRET
:您的 Auth0 应用程序的客户端密钥。
最后,您需要在 Auth0 仪表板中配置一些应用程序的 URI。将 https://127.0.0.1:3000/api/auth/callback
添加到 Allowed Callback URLs,并将 https://127.0.0.1:3000
添加到 Allowed Logout URLs 列表。
通过单击页面底部的 Save Changes 按钮保存这些配置更改。
当您将应用部署到生产环境时,可以将 localhost
替换为已部署应用的域名。Auth0 允许使用多个 URL,因此您可以同时包含 localhost
和生产 URL – 用逗号分隔。
添加 Auth0 SDK
您可以通过安装 Auth0 Next.js SDK 将 Auth0 添加到您的项目中
接下来,在 pages/api
目录中创建一个 auth/[...auth0].ts
文件,并将以下代码添加到其中
此 Next.js 动态 API 路由将自动创建以下端点
/api/auth/login
:Auth0 的登录路由。/api/auth/logout
:用于注销用户的路由。/api/auth/callback
:Auth0 在用户成功登录后重定向用户到的路由。/api/auth/me
:从 Auth0 获取用户配置文件的路由。
最后,导航到 pages/_app.tsx
文件并使用以下代码更新它,该代码使用来自 Auth0 的 UserProvider
组件包装您的应用
使用 UserProvider
组件包装 MyApp
组件将允许所有页面访问用户的身份验证状态。
保护 GraphQL API
当向 API 发送查询或 mutation 时,您可以通过包含用户信息来验证请求。您可以通过将来自 Auth0 的 user
对象附加到 GraphQL 上下文来实现。
创建一个 graphql/context.ts
文件并添加以下代码片段
来自 Auth0 的 getSession()
函数返回有关已登录用户和访问令牌的信息。然后,此数据包含在 GraphQL 上下文中。您的查询和 mutation 现在可以访问身份验证状态。
使用 createContext
函数作为其值更新带有 context
属性的服务器实例
接下来,通过指定 Context
对象的类型来更新 graphql/builder.ts
中的 SchemaBuilder
函数
最后,应用的导航栏应根据用户的身份验证状态显示 Login/Logout 按钮。使用以下代码更新 components/Layout/Header.tsx
中的 Header
组件
来自 Auth0 的 useUser
hook 检查用户是否已通过身份验证。此 hook 在客户端运行。
如果您已正确完成所有先前的步骤,您应该能够注册并登录到应用!
注意:如果您只想允许经过身份验证的请求访问您的 GraphQL API,您可以使用来自 Auth0 的
withApiAuthRequired
函数来保护它。
将 Auth0 用户与应用数据库同步
Auth0 仅代表您管理用户,并且不允许存储除用户身份验证信息之外的任何数据。因此,每当用户首次登录您的应用程序时,您需要在数据库中使用用户信息创建一个新记录。
为了实现这一点,您将利用 Auth0 Actions。Auth0 Actions 是无服务器函数,可以在 Auth0 运行时期间的特定点执行。
您将定义一个 API 路由,该路由将在登录过程中接收从 Auth0 Action 发送的信息并将信息保存到您的数据库中。这种创建 API 端点以侦听来自第三方服务事件的模式称为 webhook。
要开始使用 Auth0 Actions,请导航到位于左侧边栏的 Actions 下拉菜单,选择 Flows,然后选择 Login。
接下来,要创建新的 Action,请单击 + 图标并选择 Build custom。
为您的自定义 Action 选择一个名称,例如,“Create DB User”,然后通过选择 Create 完成该过程。
完成上一步后,您将能够管理您新创建的 Action。
以下是 Auth0 Actions UI 的细分
- 1 - 测试您的 Action
- 2 - 定义将在代码中使用的环境变量/密钥
- 3 - 包含将在 Action 代码中使用的模块
第一步是包含 node-fetch
模块版本 2.6.1
。您将在您的 Action 中使用它来向 API 端点发送请求 – 您稍后将创建此端点。此端点将处理在数据库中创建用户记录的逻辑。
接下来,定义一个密钥,该密钥将包含在 Action 发送到您的端点的每个请求中。此密钥将确保请求来自 Auth0 Action 而不是另一个不受信任的第三方。
您可以使用终端中的以下命令生成随机密钥
首先,使用密钥 AUTH0_HOOK_SECRET
将此密钥存储在 Auth0 仪表板中。
现在,还将密钥存储在您的 .env
文件中。
最后,使用以下代码更新 Action
- 检索
AUTH0_HOOK_SECRET
环境变量 - 检查用户
app_metadata
上的localUserCreated
属性 - 从登录事件中检索用户电子邮件 – 由 Auth0 提供
- 向 API 路由发送
POST
请求 –https://127.0.0.1:3000/api/auth/hook
- 将
localUserCreated
属性添加到用户的app_metadata
api.user.setAppMetadata
函数允许您向用户配置文件添加其他属性。
在您部署此 action 之前,还有一件事要做。
使用 Ngrok 暴露 localhost:3000
您创建的 Action 在 Auth0 的服务器上运行。它无法连接到您计算机上运行的 localhost:3000
。但是,您可以使用名为 Ngrok 的工具将 localhost:3000
暴露到互联网,并使其能够接收来自 Auth0 服务器的请求。
Ngrok 将为您的 localhost 服务器生成一个 URL,该 URL 可在 Auth0 Action 中使用。
待办事项:注册一个帐户,从仪表板获取令牌
在您的应用运行时,运行以下命令以暴露 localhost:3000
注意:确保将
TOKEN
值替换为 Ngrok 仪表板中的令牌。
您终端上的输出将类似于以下内容 – 但具有不同的 转发 URL
复制 转发 URL,在您的 Action 中将 localhost:3000
替换为您的 转发 URL,然后单击 Deploy。
现在 action 已部署,通过按下 Back to flow 按钮返回 Login flow。
您需要做的最后一件事是将您新创建的 action 添加到 Login flow。您将在 Custom 选项卡下找到该 action。要将 action 添加到您的 flow,您可以将其在 Start 和 Complete 之间拖放。然后单击 Apply 以保存更改。
定义用于创建新用户的 API 路由
在 pages/api/auth/
文件夹中创建一个 hook.ts
文件,并将以下代码添加到其中
此端点执行以下操作
- 验证请求是否为
POST
请求 - 验证请求正文中的
AUTH0_HOOK_SECRET
是否正确 - 验证是否在请求正文中提供了电子邮件
- 创建新的用户记录
一旦用户注册您的应用程序,用户的信息将同步到您的数据库。您可以通过 Prisma Studio 在数据库中查看新创建的用户。
创建链接 – 受身份验证保护的页面
导航到 graphql/builder.ts
文件并使用以下代码片段更新
上面的代码片段在模式中注册了 Mutation
类型,这允许您在 GraphQL 服务器中定义 mutation。
接下来,使用以下 mutation 更新 graphql/types/Link.ts
,该 mutation 添加了创建链接的功能
args
属性定义了创建新链接所需的输入。mutation 还会检查用户是否已登录,以便只有经过身份验证的用户才能创建链接。最后,Prisma 中的 create()
函数会创建一个新的数据库记录。
安装以下您将用于表单管理和通知的依赖项
接下来,创建 pages/admin.tsx
页面并添加以下代码。该代码允许创建新链接
onSubmit
函数将表单值传递给 createLink
mutation。当 mutation 正在执行时,将显示一个 toast – 成功、加载或错误。
在 getServerSideProps
中,如果没有会话,您将用户重定向到登录页面。如果找到与已登录用户的电子邮件匹配的用户记录,则渲染 /admin
页面。
通过添加一个 + Create 按钮来更新 Header.tsx
文件,经过身份验证的用户可以使用该按钮来创建链接。
您现在应该能够创建链接了!🚀
奖励:根据用户角色保护页面
您可以通过确保只有管理员用户才能创建链接来加强身份验证。
首先,更新 createLink
mutation 以检查用户的角色
通过在您的 getServerSideProps
中添加角色检查来更新 admin.tsx
页面,以重定向不是管理员的用户。没有 ADMIN
角色的用户将被重定向到 /404
页面。
注册时分配给用户的默认角色是 USER
。因此,如果您尝试转到 /admin
页面,它将不再有效。
您可以通过修改数据库中用户的 role
字段来更改此设置。这在 Prisma Studio 中非常容易做到。
首先在终端中运行 npx prisma studio
启动 Prisma Studio。然后单击 User 模型并找到与当前用户匹配的记录。现在,继续将您的用户角色从 USER
更新为 ADMIN
。通过按下 Save 1 change 按钮保存您的更改。
导航到您应用程序的 /admin
页面,瞧!您现在可以再次创建链接了。
总结和下一步
在这一部分中,您学习了如何使用 Auth0 将身份验证和授权添加到 Next.js 应用,以及如何使用 Auth0 Actions 将用户添加到数据库。
请继续关注下一部分,您将在其中学习如何使用 AWS S3 添加图片上传。
不要错过下一篇文章!
注册 Prisma 新闻通讯