跳至內容
從 NextAuth.js v4 遷移?請閱讀 我們的遷移指南.
指南頁面自訂登入

自訂登入頁面

若要新增自訂登入頁面,您需要在 Auth.js 設定中的 pages 物件中定義頁面的路徑。請確保您在此定義的路徑上確實存在路由/頁面!

此外,我們必須匯出 provider.idprovider.name 的對應,以便在自訂頁面中輕鬆使用,如果我們想要根據在 auth.ts 設定中定義的內容動態呈現正確的按鈕。因為您可以將供應商作為函數或呼叫該函數的結果傳遞給 providers 陣列,所以此範例 providerMap 可以處理這兩種情況。

./auth.ts
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"
import Credentials from "next-auth/providers/credentials"
import type { Provider } from "next-auth/providers"
 
const providers: Provider[] = [
  Credentials({
    credentials: { password: { label: "Password", type: "password" } },
    authorize(c) {
      if (c.password !== "password") return null
      return {
        id: "test",
        name: "Test User",
        email: "test@example.com",
      }
    },
  }),
  GitHub,
]
 
export const providerMap = providers
  .map((provider) => {
    if (typeof provider === "function") {
      const providerData = provider()
      return { id: providerData.id, name: providerData.name }
    } else {
      return { id: provider.id, name: provider.name }
    }
  })
  .filter((provider) => provider.id !== "credentials")
 
export const { handlers, auth, signIn, signOut } = NextAuth({
  providers,
  pages: {
    signIn: "/signin",
  },
})

現在我們可以建立自己的自訂登入頁面。

app/signin/page.tsx
import { redirect } from "next/navigation"
import { signIn, auth, providerMap } from "@/auth.ts"
import { AuthError } from "next-auth"
 
export default async function SignInPage(props: {
  searchParams: { callbackUrl: string | undefined }
}) {
  return (
    <div className="flex flex-col gap-2">
      <form
        action={async (formData) => {
          "use server"
          try {
            await signIn("credentials", formData)
          } catch (error) {
            if (error instanceof AuthError) {
              return redirect(`${SIGNIN_ERROR_URL}?error=${error.type}`)
            }
            throw error
          }
        }}
      >
        <label htmlFor="email">
          Email
          <input name="email" id="email" />
        </label>
        <label htmlFor="password">
          Password
          <input name="password" id="password" />
        </label>
        <input type="submit" value="Sign In" />
      </form>
      {Object.values(providerMap).map((provider) => (
        <form
          action={async () => {
            "use server"
            try {
              await signIn(provider.id, {
                redirectTo: props.searchParams?.callbackUrl ?? "",
              })
            } catch (error) {
              // Signin can fail for a number of reasons, such as the user
              // not existing, or the user not having the correct role.
              // In some cases, you may want to redirect to a custom error
              if (error instanceof AuthError) {
                return redirect(`${SIGNIN_ERROR_URL}?error=${error.type}`)
              }
 
              // Otherwise if a redirects happens Next.js can handle it
              // so you can just re-thrown the error and let Next.js handle it.
              // Docs:
              // https://nextjs.dev.org.tw/docs/app/api-reference/functions/redirect#server-component
              throw error
            }
          }}
        >
          <button type="submit">
            <span>Sign in with {provider.name}</span>
          </button>
        </form>
      ))}
    </div>
  )
}

然後,當在應用程式中的任何位置呼叫不帶任何引數的 signIn 時,將會出現自訂登入頁面。

Custom Sign-in Page
Auth.js © Balázs Orbán 和團隊 -2024