2022 年 1 月 28 日
使用 TypeScript、PostgreSQL、Next.js、Prisma 和 GraphQL 開發全端應用程式:身份驗證
本文是課程的第三部分,您將在其中使用 Next.js、GraphQL、TypeScript、Prisma 和 PostgreSQL 建構全端應用程式。在本文中,您將學習如何為您的應用程式新增身份驗證。
目錄
簡介
在本課程中,您將學習如何建構「awesome-links」,這是一個全端應用程式,使用者可以在其中瀏覽精選連結列表並為他們最喜歡的連結加上書籤。
在第二部分中,您使用 GraphQL Yoga 和 Pothos 建構了 GraphQL API。然後,您使用了 Apollo Client 在前端使用 GraphQL API。
開發環境
若要跟隨本教學課程進行操作,請確保您已安裝Node.js和GraphQL 擴充功能。您還需要一個正在運行的 PostgreSQL 資料庫。
如果您是從第二部分開始跟隨,則可以跳過專案設定,直接跳到使用 Auth0 進行身份驗證和保護 GraphQL API章節。
注意:您可以在本機設定 PostgreSQL,或在 Heroku 上設定託管實例。在本課程結束時的部署步驟中,您將需要遠端資料庫。
複製儲存庫
您可以在 GitHub 上找到本課程的完整原始碼。
注意:每篇文章都有一個對應的分支。這樣,您就可以在閱讀時跟隨操作。透過檢視part-3 分支,您將擁有與本文相同的起點。每個分支之間可能存在一些差異,因此為了避免遇到任何問題,建議您複製本文的分支。
若要開始使用,請導航到您選擇的目錄中,並執行以下命令以複製儲存庫
導航到複製的應用程式中並安裝依賴項
初始化資料庫
設定 PostgreSQL 資料庫後,將 env.example
檔案重新命名為 .env
,並設定資料庫的連線字串。之後,執行以下命令以在資料庫中建立資料表
有關連線字串格式的更多詳細資訊,請參閱第一部分 – 將 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 – 一個隨插即用的身份驗證和授權解決方案。
在建立帳戶後,導航至位於左側邊欄的應用程式下拉式選單,然後從子選單中選擇應用程式。
接下來,按一下+ 建立應用程式按鈕以建立新應用程式。為您的應用程式命名,選擇常規 Web 應用程式,然後透過選擇對話方塊右下角的建立按鈕完成應用程式的建立。
成功建立應用程式後,導航至設定標籤,並將以下資訊複製到專案的 .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
新增至允許的回呼 URL,並將 https://127.0.0.1:3000
新增至允許的登出 URL 列表。
按一下頁面底部的儲存變更按鈕,以儲存這些設定變更。
當您將應用程式部署到生產環境時,您可以將 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 時,您可以透過包含使用者資訊來驗證請求。您可以透過將來自 Auth0 的 user
物件附加到 GraphQL 上下文來執行此操作。
建立一個 graphql/context.ts
檔案並新增以下程式碼片段
Auth0 的 getSession()
函數傳回有關已登入使用者和存取權杖的資訊。然後,此資料會包含在 GraphQL 上下文中。您的查詢和變更現在可以存取身份驗證狀態。
使用 createContext
函數作為其值來更新具有 context
屬性的伺服器實例
接下來,透過指定 Context
物件的類型,來更新 graphql/builder.ts
中的 SchemaBuilder
函數
最後,應用程式的導航欄應根據使用者的身份驗證狀態顯示登入/登出按鈕。使用以下程式碼更新 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,請導航至位於左側邊欄的動作下拉式選單,選擇流程,然後選擇登入。
接下來,若要建立新動作,請按一下+圖示,然後選擇建構自訂。
為您的自訂動作選擇一個名稱,例如「建立資料庫使用者」,然後透過選擇建立來完成該過程。
完成上一個步驟後,您將能夠管理您新建立的動作。
以下是 Auth0 Actions UI 的細分
- 1 - 測試您的動作
- 2 - 定義將在程式碼中使用的環境變數/密碼
- 3 - 包含將在動作程式碼中使用的模組
第一步是包含 node-fetch
模組版本 2.6.1
。您將在您的動作中使用它來向 API 端點傳送請求 – 您稍後將建立此端點。此端點將處理在資料庫中建立使用者記錄的邏輯。
接下來,定義一個密碼,該密碼將包含在動作傳送至您的端點的每個請求中。此密碼將確保請求來自 Auth0 Action 而不是另一個不受信任的第三方。
您可以使用終端機中的以下命令來產生隨機密碼
首先,使用金鑰 AUTH0_HOOK_SECRET
將此密碼儲存在 Auth0 儀表板中。
現在,也將密碼儲存在您的 .env
檔案中。
最後,使用以下程式碼更新動作
- 擷取
AUTH0_HOOK_SECRET
環境變數 - 檢查使用者
app_metadata
上的localUserCreated
屬性 - 從登入事件中擷取使用者的電子郵件 – 由 Auth0 提供
- 向 API 路由傳送
POST
請求 –https://127.0.0.1:3000/api/auth/hook
- 將
localUserCreated
屬性新增至使用者的app_metadata
api.user.setAppMetadata
函數允許您將其他屬性新增至使用者設定檔。
在您部署此動作之前,還有一件事要做。
使用 Ngrok 公開 localhost:3000
您建立的動作在 Auth0 的伺服器上運行。它無法連線到您電腦上運行的 localhost:3000
。但是,您可以使用名為 Ngrok 的工具將 localhost:3000
公開到網際網路,並使其能夠接收來自 Auth0 伺服器的請求。
Ngrok 將為您的 localhost 伺服器產生一個 URL,該 URL 可在 Auth0 Action 中使用。
待辦事項:註冊帳戶,從儀表板取得權杖
在您的應用程式運行時,執行以下命令以公開 localhost:3000
注意:請務必將
TOKEN
值替換為 Ngrok 儀表板中的權杖。
終端機上的輸出將與以下內容類似 – 但具有不同的轉發 URL
複製轉發 URL,在您的動作中將 localhost:3000
替換為您的轉發 URL,然後按一下部署。
現在動作已部署,請按一下返回流程按鈕返回登入流程。
您需要做的最後一件事是將您新建立的動作新增至登入流程。您將在自訂標籤下方找到該動作。若要將動作新增至您的流程,您可以將其拖放到開始和完成之間。然後按一下套用以儲存變更。
定義用於建立新使用者的 API 路由
在 pages/api/auth/
資料夾中建立一個 hook.ts
檔案,並在其中新增以下程式碼
此端點執行以下操作
- 驗證請求是否為
POST
請求 - 驗證請求正文中的
AUTH0_HOOK_SECRET
是否正確 - 驗證請求正文中是否提供了電子郵件
- 建立新的使用者記錄
一旦使用者註冊到您的應用程式,使用者的資訊將同步到您的資料庫。您可以透過 Prisma Studio 在您的資料庫中檢視新建立的使用者。
建立連結 – 受身份驗證保護的頁面
導航至 graphql/builder.ts
檔案,並使用以下程式碼片段更新
以上程式碼片段在結構描述中註冊 Mutation
類型,這允許您在 GraphQL 伺服器中定義變更。
接下來,使用以下變更更新 graphql/types/Link.ts
,該變更新增了建立連結的功能
args
屬性定義了建立新連結所需的輸入。變更還會檢查使用者是否已登入,因此只有通過身份驗證的使用者才能建立連結。最後,Prisma 的 create()
函數會建立新的資料庫記錄。
安裝以下您將用於表單管理和通知的依賴項
接下來,建立 pages/admin.tsx
頁面並新增以下程式碼。該程式碼允許建立新連結
onSubmit
函數將表單值傳遞給 createLink
變更。在執行變更時,將顯示 toast – 成功、載入中或錯誤。
在 getServerSideProps
中,如果沒有會期,您將使用者重新導向到登入頁面。如果找到與已登入使用者的電子郵件相符的使用者記錄,則會呈現 /admin
頁面。
透過新增經過身份驗證的使用者可以用於建立連結的 + 建立按鈕來更新 Header.tsx
檔案。
您現在應該能夠建立連結了!🚀
額外內容:根據使用者角色保護頁面
您可以透過確保只有管理員使用者才能建立連結來加強身份驗證。
首先,更新 createLink
變更以檢查使用者的角色
透過在您的 getServerSideProps
中新增角色檢查來更新 admin.tsx
頁面,以重新導向非管理員使用者。沒有 ADMIN
角色的使用者將被重新導向到 /404
頁面。
註冊時分配給使用者的預設角色為 USER
。因此,如果您嘗試轉到 /admin
頁面,它將不再起作用。
您可以透過修改資料庫中使用者的 role
欄位來變更此設定。這在 Prisma Studio 中非常容易做到。
首先,透過在終端機中運行 npx prisma studio
來啟動 Prisma Studio。然後按一下使用者模型,並找到與目前使用者相符的記錄。現在,繼續將您的使用者角色從 USER
更新為 ADMIN
。按一下儲存 1 個變更按鈕來儲存您的變更。
導航至您應用程式的 /admin
頁面,瞧!您現在可以再次建立連結了。
摘要和後續步驟
在本部分中,您學習了如何使用 Auth0 將身份驗證和授權新增至 Next.js 應用程式,以及如何使用 Auth0 Actions 將使用者新增至您的資料庫。
請繼續關注下一部分,您將在其中學習如何使用 AWS S3 新增圖片上傳。
不要錯過下一篇文章!
註冊 Prisma 電子報