跳至內容
從 NextAuth.js v4 遷移?請閱讀 我們的遷移指南.
指南Edge 相容性

隨著 Edge 執行環境越來越普及,人們自然會嘗試在這些環境中部署 Auth.js 和 next-auth,並且目前遇到了困擾整個生態系統的一些基本相容性問題。我們希望透過這份文件,無論人們目前對理解和經驗處於什麼階段,我們都能幫助他們理解挑戰,並希望讓 Auth.js 在他們選擇的任何執行環境中都能正常運作!

首先,讓我們開始了解一些背景知識。如果您已經熟悉這些內容,請隨意跳過此部分!

定義

我們將特別討論 Auth.js 以及它如何與當今各種框架、託管提供商、函式庫等非常流行的邊緣執行環境產生交集。

首先,在這個上下文中,「邊緣」是什麼?這裡的邊緣是借用自網路工程人員,指的是位於網路邊緣(即更靠近使用者)的運算節點(即伺服器)。通常,這些運算節點的功率低於在資料中心核心中找到的完整伺服器,而這些伺服器運行大多數重要的工作負載。在這裡運行程式碼的一些優點包括降低使用者終端裝置的延遲、更好的可擴展性故事以及更具成本效益的運算。一些缺點包括硬體功能較弱,以及在軟體堆疊方面可能存在不同的相容性。

因此,當我們說 邊緣執行環境時,我們指的是一個伺服器端 JavaScript 執行環境,它不是 Node.js,並且經過優化以在這些邊緣運算節點(伺服器)上運行。這通常表示程式碼在更靠近使用者的低功耗硬體上執行,這些硬體針對快速啟動時間、低記憶體使用量等其他方面進行了優化。

這是一個問題,因為這些執行環境通常缺少 Node.js 具有的功能,有時這些功能對於您所依賴的函式庫和套件的運作至關重要。當套件說它「與邊緣相容」或「已準備好邊緣環境」時,它們真正的意思是他們已經設計他們的軟體以避免在某些邊緣執行環境中遺失的任何 Node.js 功能/模組,從而使其更具普遍相容性。請查看 unjs 的相容性矩陣,以了解哪些執行環境支援哪些功能。雖然對 Auth.js 並非至關重要,但這裡值得一提的是,有一個產業組織旨在為 JavaScript 執行環境提供一個協作 API 互通性的空間 - WinterCG

💡

我想在這裡指出,這些功能/模組通常遺失,因為它們運行的基礎環境不提供它們。例如,開發人員可以投入盡可能多的時間,但如果他們的伺服器端 JavaScript 執行環境將在一個沙箱作業系統環境中運行,而該環境不允許他們存取檔案系統,那麼無論他們多麼努力,都將無法實作 fs 模組。

由於目前這種 Node.js 與其他執行環境的情況非常分散且不穩定,許多函式庫正在優化其工作負載,僅使用最常見的公分母功能,例如 fetch。例如,如果您是資料庫提供者,並且您可以設計您的系統,以便您的用戶端函式庫只需要發出 HTTP 請求與您的後端通信,那麼您可以將您的函式庫宣傳為「與邊緣相容」,並在您的使用者可能想要使用的任何位置運行。這與其他必須使用來自 Node.js 的原始 TCP 通訊端來與其後端通信的資料庫用戶端函式庫形成對比。

Auth.js

Edge 相容性是 Auth.js 已針對其進行優化的功能。這表示您可以在您選擇的任何 JavaScript 執行環境上執行核心 Auth.js 功能。但是,這裡的關鍵字是核心功能。如果您使用 Auth.js / next-auth 且在 Auth.js 回呼、中介軟體等中不使用其他函式庫,那麼您可以在任何您想要的地方使用它!

當您想要將其他函式庫與 Auth.js 一起使用時,問題就會開始出現。

問題

資料庫介面卡

與 Auth.js 配對以實作整體驗證系統的一個常見套件是資料庫用戶端。資料庫用戶端很麻煩,因為它們通常會利用 TCP 通訊端直接與資料庫伺服器通信。PostgreSQL 就是一個這樣做的常見資料庫。

PostgreSQL 是一個資料庫,它使用基於訊息的協定在用戶端和伺服器之間進行通信,該協定透過 TCP(或 Unix)通訊端傳輸。原始 TCP 通訊端是 Node.js 的其中一個功能,通常邊緣執行環境無法使用。因此,從表面上看,似乎無法從在邊緣執行環境上執行的 JavaScript 與 PostgreSQL 資料庫通信。許多其他資料庫及其各自的通信協定也是如此。

但是,隨著邊緣執行環境的成熟和普及,人們發揮了創造力並實作了針對此問題的各種解決方案。其中一種常見的解決方案是在資料庫前面放置某種類型的 API 伺服器,其目標是將透過 HTTP 發送給它的資料庫查詢轉換為資料庫可以理解的協定。這允許用戶端僅對 API 伺服器發出 HTTP 請求,這是每個邊緣執行環境都支援的。

中介軟體

在 Next.js 和 next-auth 中,您也可以使用 Next.js 中介軟體,透過檢查是否存在 Session 並決定接下來的路由位置來保護路由。預設情況下,在 Vercel 和其他託管提供商上,中介軟體程式碼始終在邊緣執行環境中運行。這表示我們的程式碼將嘗試在一個基礎功能不可用的環境(即 TCP 通訊端)中執行 PostgreSQL 查詢。因此,要使用非明確「與邊緣相容」的資料庫介面卡,我們需要找到一種方法,使用我們可用的功能來查詢資料庫

解決方案

Auth.js 與資料庫 Session 策略及資料庫介面卡搭配使用時,在正常操作期間會多次呼叫資料庫。無論您使用哪個框架,每個 Auth.js 客戶端都可以提取目前活動的 Session,這是透過查詢資料庫以檢查使用者的 sessionToken 是否存在於資料庫中且有效(即未過期)來完成的。

這表示在您應用程式中任何可能需要檢查使用者是否已通過身份驗證的地方,都需要呼叫資料庫。實際上,Auth.js 在這方面更為聰明,它會使用快取和其他技巧來避免不必要的資料庫請求,但您可以想像每次呼叫 auth() 都會觸發資料庫查詢。因此,我們需要某種變通方法,以便在具有許多資料庫介面卡的邊緣執行環境中使用 Auth.js!

分割設定

考量到 Next.js 和 next-auth,讓我們思考一下,為了讓 Auth.js 能夠在邊緣執行環境中執行某些程式碼,同時也能使用資料庫儲存其 Session,我們需要做些什麼。我們需要一個獨立版本的 next-auth,其中不包含邊緣環境的資料庫設定,以及另一個包含其他地方資料庫的版本。為了實現這一點,我們可以利用 Auth.js 的「延遲初始化」功能,來實例化一個獨立的客戶端,此客戶端在 middleware 中不帶介面卡,而另一個客戶端則在其他地方使用。

  1. 首先,一個通用的 Auth.js 設定物件,可以在任何地方使用。此物件不會包含資料庫介面卡。
auth.config.ts
import GitHub from "next-auth/providers/github"
import type { NextAuthConfig } from "next-auth"
 
// Notice this is only an object, not a full Auth.js instance
export default {
  providers: [GitHub],
} satisfies NextAuthConfig
  1. 接下來,一個獨立的實例化 Auth.js 實例,它會導入該設定,同時也會加入介面卡,並使用 jwt 作為 Session 策略
auth.ts
import NextAuth from "next-auth"
import authConfig from "./auth.config"
 
import { PrismaClient } from "@prisma/client"
import { PrismaAdapter } from "@auth/prisma-adapter"
 
const prisma = new PrismaClient()
 
export const { handlers, auth, signIn, signOut } = NextAuth({
  adapter: PrismaAdapter(prisma),
  session: { strategy: "jwt" },
  ...authConfig,
})
  1. 我們的 Middleware,會導入不含資料庫介面卡的設定,並實例化其自己的 Auth.js 客戶端。
middleware.ts
import NextAuth from "next-auth"
import authConfig from "./auth.config"
 
export const { auth: middleware } = NextAuth(authConfig)
  1. 最後,在其他任何地方,我們都可以從主要的 auth.ts 設定導入,並像往常一樣使用 next-auth。請參閱我們的Session 管理文件以取得更多範例。
app/protected/page.tsx
import { auth } from "@/auth"
 
export default async function Page() {
  const session = await auth()
 
  if (!session) {
    return <div>Not authenticated</div>
  }
 
  return (
    <div className="container">
      <pre>{JSON.stringify(session, null, 2)}</pre>
    </div>
  )
}

這裡需要特別注意的是,我們現在已從 middleware 中的 next-auth 中移除了資料庫功能和支援。這表示當在 middleware 中執行程式碼時,我們將無法提取 Session 或其他資訊,例如使用者的帳戶詳細資料等。這表示您需要依賴像上面在 /app/protected/page.tsx 檔案中展示的檢查,以確保您能有效地保護您的路由。舉例來說,Middleware 仍然用於延長 Session Cookie 的過期時間。

Auth.js © Balázs Orbán 和團隊 -2024