跳至內容
從 NextAuth.js v4 遷移?請閱讀 我們的遷移指南.
API 參考@auth/sveltekit

@auth/sveltekit

⚠️

@auth/sveltekit 目前為實驗性質。API *可能*會變更。

SvelteKit Auth 是 Auth.js 的官方 SvelteKit 整合。它提供一種簡單的方法,只需幾行程式碼即可將身份驗證新增至您的 SvelteKit 應用程式。

安裝

npm install @auth/sveltekit

用法

src/auth.ts
 
import { SvelteKitAuth } from "@auth/sveltekit"
import GitHub from "@auth/sveltekit/providers/github"
 
export const { handle, signIn, signOut } = SvelteKitAuth({
  providers: [GitHub],
})

延遲初始化

@auth/sveltekit 支援延遲初始化,您可以在其中讀取 event 物件,以延遲設定設定。當您必須從 event.platform 取得 Cloudflare Workers 等平台的環境變數時,此功能特別有用。

src/auth.ts
import { SvelteKitAuth } from "@auth/sveltekit"
import GitHub from "@auth/sveltekit/providers/github"
 
export const { handle, signIn, signOut } = SvelteKitAuth(async (event) => {
  const authOptions = {
    providers: [
      GitHub({
        clientId: event.platform.env.AUTH_GITHUB_ID,
        clientSecret: event.platform.env.AUTH_GITHUB_SECRET
      })
    ],
    secret: event.platform.env.AUTH_SECRET,
    trustHost: true
  }
  return authOptions
})

src/hooks.server.ts 中重新匯出 handle

src/hooks.server.ts
export { handle } from "./auth"

請記住設定 AUTH_SECRET 環境變數。這應該是至少 32 個字元的隨機字串。在 UNIX 系統上,您可以使用 openssl rand -hex 32 或查看 https://generate-secret.vercel.app/32

當在 Vercel 之外部署應用程式時,請針對其他託管供應商 (例如 Cloudflare Pages 或 Netlify) 將 AUTH_TRUST_HOST 變數設定為 true

提供者使用的回呼 URL 必須設定為以下內容,除非您覆寫 SvelteKitAuthConfig.basePath

[origin]/auth/callback/[provider]

登入和登出

伺服器端

<SignIn /><SignOut />@auth/sveltekit 開箱即用提供的元件 - 它們會處理登入/登出流程,而且可以按原樣用作起點,或針對您自己的元件進行自訂。以下範例說明如何使用 SignInSignOut 元件,使用 SvelteKit 的伺服器端表單動作登入和登出。您需要兩件事才能讓這一切正常運作

  1. 在 SvelteKit 應用程式的前端中使用元件
  2. /signin (適用於 SignIn) 和 /signout (適用於 SignOut) 新增必要的 page.server.ts,以處理表單動作
<script>
  import { SignIn, SignOut } from "@auth/sveltekit/components"
  import { page } from "$app/stores"
</script>
 
<h1>SvelteKit Auth Example</h1>
<div>
  {#if $page.data.session}
    {#if $page.data.session.user?.image}
      <img
        src={$page.data.session.user.image}
        class="avatar"
        alt="User Avatar"
      />
    {/if}
    <span class="signedInText">
      <small>Signed in as</small><br />
      <strong>{$page.data.session.user?.name ?? "User"}</strong>
    </span>
    <SignOut>
      <div slot="submitButton" class="buttonPrimary">Sign out</div>
    </SignOut>
  {:else}
    <span class="notSignedInText">You are not signed in</span>
    <SignIn>
      <div slot="submitButton" class="buttonPrimary">Sign in</div>
    </SignIn>
    <SignIn provider="facebook"/>
  {/if}
</div>

若要設定表單動作,我們需要在 src/routes 中定義檔案

src/routes/signin/+page.server.ts
import { signIn } from "../../auth"
import type { Actions } from "./$types"
export const actions: Actions = { default: signIn }
src/routes/signout/+page.server.ts
import { signOut } from "../../auth"
import type { Actions } from "./$types"
export const actions: Actions = { default: signOut }

這些路由可以使用各自元件上的 signInPagesignOutPage 屬性進行自訂。

客戶端

我們也從 @auth/sveltekit/client 匯出兩種方法,以便執行用戶端登入和登出動作。

src/routes/index.svelte
import { signIn, signOut } from "@auth/sveltekit/client"
 
<nav>
  <p>
    These actions are all using the methods exported from
    <code>@auth/sveltekit/client</code>
  </p>
  <div class="actions">
    <div class="wrapper-form">
      <button on:click={() => signIn("github")}>Sign In with GitHub</button>
    </div>
    <div class="wrapper-form">
      <button on:click={() => signIn("discord")}>Sign In with Discord</button>
    </div>
    <div class="wrapper-form">
      <div class="input-wrapper">
        <label for="password">Password</label>
        <input
          bind:value={password}
          type="password"
          id="password"
          name="password"
          required
        />
      </div>
      <button on:click={() => signIn("credentials", { password })}>
        Sign In with Credentials
      </button>
      <button on:click={() => signOut()})}>
        Sign Out
      </button>
    </div>
  </div>
</nav>

管理 Session

以上範例會檢查 $page.data.session 中是否有可用的 Session,不過這需要我們在某處進行設定。如果您希望所有路由都能使用此資料,您可以將其新增至 src/routes/+layout.server.ts。以下程式碼會在 $page 儲存中設定 Session 資料,使其可供所有路由使用。

import type { LayoutServerLoad } from './$types';
 
export const load: LayoutServerLoad = async (event) => {
  return {
    session: await event.locals.auth()
  };
};

您在函式 LayoutServerLoad 中回傳的內容,將會在 $page 儲存內的 data 屬性中可用:$page.data。在此情況下,我們會回傳具有 'session' 屬性的物件,這就是我們在其他程式碼路徑中存取的内容。

處理授權

在 SvelteKit 中,您可以使用幾種方法來保護路由免受未驗證的使用者存取。

每個元件

最簡單的情況是保護單一頁面,在這種情況下,您應該將邏輯放在 +page.server.ts 檔案中。請注意,在這種情況下,您也可以等待 event.parent 並從那裡取得 Session,但是即使您尚未在根 +layout.server.ts 中執行上述操作,此實作方式也能運作

import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
 
export const load: PageServerLoad = async (event) => {
  const session = await event.locals.auth();
  if (!session?.user) throw redirect(303, '/auth');
  return {};
};
🚫

PageLoad 的情況下,請務必**總是**從父元件取得 session 資訊,而不是使用 store 中的資訊。若不這樣做,可能會導致使用者在該頁面載入時,+layout.server.ts 沒有執行,因而錯誤地存取受保護的資訊。此程式碼範例已經使用 const { session } = await parent(); 實作正確的方法。有關 SvelteKit 的 load 功能行為及其對身份驗證的影響的更多資訊,請參閱此 SvelteKit 文件章節

您**不應**將授權邏輯放在 +layout.server.ts 中,因為無法保證該邏輯會傳遞到樹狀結構中的葉節點。建議透過 +page.server.ts 檔案手動保護每個路由,以避免錯誤。雖然可以強制版面配置檔案在所有路由上執行載入函式,但這依賴於可能會變化的某些行為,並且不容易檢查。有關這些注意事項的更多資訊,請務必閱讀 SvelteKit 儲存庫中的這個問題:https://github.com/sveltejs/kit/issues/6315

依路徑劃分

另一種處理授權的方法是限制某些 URI 的可用性。對許多專案來說,這更好,因為

  • 這會自動保護這些 URI 中的 actions 和 api 路由
  • 元件之間沒有重複的程式碼
  • 非常容易修改

透過 URI 處理授權的方式是覆寫您的 handle hook。從 src/auth.ts 中的 SvelteKitAuth 返回的 handle hook 是一個函式,旨在接收發送到您的 SvelteKit 網路應用程式的所有請求。您應該從 src/auth.ts 匯出它,並將其匯入到您的 src/hooks.server.ts 中。若要在 hooks.server.ts 中使用多個 handle,我們可以使用 SvelteKit 的 sequence 依序執行它們。

src/auth.ts
import { SvelteKitAuth } from '@auth/sveltekit';
import GitHub from '@auth/sveltekit/providers/github';
 
export const { handle, signIn, signOut } = SvelteKitAuth({
  providers: [GitHub]
}),
src/hooks.server.ts
import { redirect, type Handle } from '@sveltejs/kit';
import { handle as authenticationHandle } from './auth';
import { sequence } from '@sveltejs/kit/hooks';
 
async function authorizationHandle({ event, resolve }) {
  // Protect any routes under /authenticated
  if (event.url.pathname.startsWith('/authenticated')) {
    const session = await event.locals.auth();
    if (!session) {
      // Redirect to the signin page
      throw redirect(303, '/auth/signin');
    }
  }
 
  // If the request is still here, just proceed as normally
  return resolve(event);
}
 
// First handle authentication, then authorization
// Each function acts as a middleware, receiving the request handle
// And returning a handle which gets passed to the next function
export const handle: Handle = sequence(authenticationHandle, authorizationHandle)

在這裡了解更多有關 SvelteKit 的 handle hooks 和 sequence 的資訊 這裡

現在,/authenticated 下的所有路由都將由 handle hook 透明地保護。您可以向 sequence 中新增更多類似中介軟體的函式,並在此檔案中實作更複雜的授權業務邏輯。如果需要保護特定頁面,並且透過 URI 進行保護可能會出錯,也可以將其與基於元件的方法一起使用。

注意事項

  • 如果您使用啟用 prerender 的方式來建置 SvelteKit 應用程式,則具有指向預設登入頁面錨點標籤(例如 <a href="/auth/signin" ...)的頁面將在建置時遇到問題。請改用 內建函式或元件來登入或登出。

在這裡了解更多關於 @auth/sveltekit 的資訊 這裡

SvelteKitAuthConfig

重新匯出 SvelteKitAuthConfig

AuthError

所有 Auth.js 錯誤的基本錯誤類別。它經過最佳化,可透過 logger.error 選項,以格式良好的方式印在伺服器記錄中。

擴展

建構函式

new AuthError(message, errorOptions)

new AuthError(message?, errorOptions?): AuthError
參數
參數類型
message?string | ErrorOptions
errorOptions?ErrorOptions
回傳

AuthError

覆寫

Error.constructor

屬性

cause?

optional cause: Record<string, unknown> & {
  err: Error;
};
類型宣告
err?
optional err: Error;
覆寫

Error.cause

message

message: string;
繼承自

Error.message

name

name: string;
繼承自

Error.name

stack?

optional stack: string;
繼承自

Error.stack

type

type: ErrorType;

錯誤類型。用於在記錄中識別錯誤。

prepareStackTrace()?

static optional prepareStackTrace: (err, stackTraces) => any;

格式化堆疊追蹤的可選覆寫

請參閱

https://v8.dev.org.tw/docs/stack-trace-api#customizing-stack-traces

參數
參數類型
errError
stackTracesCallSite[]
回傳

any

繼承自

Error.prepareStackTrace

stackTraceLimit

static stackTraceLimit: number;
繼承自

Error.stackTraceLimit

方法

captureStackTrace()

static captureStackTrace(targetObject, constructorOpt?): void

在目標物件上建立 .stack 屬性

參數
參數類型
targetObjectobject
constructorOpt?Function
回傳

void

繼承自

Error.captureStackTrace


CredentialsSignin

可以從 Credentials 供應商的 authorize 回呼中擲出。當 authorize 回呼期間發生錯誤時,可能會發生兩種情況

  1. 使用者會被重新導向到登入頁面,網址中帶有 error=CredentialsSignin&code=credentialscode 是可設定的。
  2. 如果您在處理表單動作伺服器端的框架中擲出此錯誤,則會擲出此錯誤,而不是重新導向使用者,因此您需要處理。

擴展

建構函式

new CredentialsSignin(message, errorOptions)

new CredentialsSignin(message?, errorOptions?): CredentialsSignin
參數
參數類型
message?string | ErrorOptions
errorOptions?ErrorOptions
回傳

CredentialsSignin

繼承自

SignInError.constructor

屬性

cause?

optional cause: Record<string, unknown> & {
  err: Error;
};
類型宣告
err?
optional err: Error;
繼承自

SignInError.cause

code

code: string;

在重新導向 URL 的 code 查詢參數中設定的錯誤碼。

⚠ 注意:此屬性將包含在 URL 中,因此請確保它不會暗示敏感錯誤。

如果您需要除錯,則完整的錯誤始終會記錄在伺服器上。

一般來說,我們不建議明確暗示使用者是否輸入了錯誤的使用者名稱或密碼,請嘗試使用類似「無效憑證」的內容。

message

message: string;
繼承自

SignInError.message

name

name: string;
繼承自

SignInError.name

stack?

optional stack: string;
繼承自

SignInError.stack

type

type: ErrorType;

錯誤類型。用於在記錄中識別錯誤。

繼承自

SignInError.type

種類

static kind: string;
繼承自

SignInError.kind

prepareStackTrace()?

static optional prepareStackTrace: (err, stackTraces) => any;

格式化堆疊追蹤的可選覆寫

參見

https://v8.dev.org.tw/docs/stack-trace-api#customizing-stack-traces

參數
參數類型
errError
stackTracesCallSite[]
回傳值

any

繼承自

SignInError.prepareStackTrace

stackTraceLimit

static stackTraceLimit: number;
繼承自

SignInError.stackTraceLimit

類型

static type: string;

方法

captureStackTrace()

static captureStackTrace(targetObject, constructorOpt?): void

在目標物件上建立 .stack 屬性

參數
參數類型
targetObjectobject
constructorOpt?Function
回傳值

void

繼承自

SignInError.captureStackTrace


帳戶

通常包含有關所使用的供應商的資訊,並且還擴展了 TokenSet,這是 OAuth 供應商返回的不同令牌。

擴展自

屬性

access_token?

optional readonly access_token: string;
繼承自

Partial.access_token

authorization_details?

optional readonly authorization_details: AuthorizationDetails[];
繼承自

Partial.authorization_details

expires_at?

optional expires_at: number;

根據 TokenEndpointResponse.expires_in 計算的值。

這是 TokenEndpointResponse.access_token 過期的絕對時間戳記(以秒為單位)。

此值可用於與 TokenEndpointResponse.refresh_token 一起實作令牌輪換。

參見

expires_in?

optional readonly expires_in: number;
繼承自

Partial.expires_in

id_token?

optional readonly id_token: string;
繼承自

Partial.id_token

供應商

provider: string;

此帳戶的供應商 ID。例如「google」。請參閱 https://authjs.dev.org.tw/reference/core/providers 上的完整清單

providerAccountId

providerAccountId: string;

此值取決於用於建立帳戶的供應商類型。

  • oauth/oidc:OAuth 帳戶的 ID,從 profile() 回呼返回。
  • email:使用者的電子郵件地址。
  • credentials:從 authorize() 回呼返回的 id

refresh_token?

optional readonly refresh_token: string;
繼承自

Partial.refresh_token

scope?

optional readonly scope: string;
繼承自

Partial.scope

token_type?

optional readonly token_type: Lowercase<string>;

注意:因為值不區分大小寫,所以它總是返回小寫

繼承自

Partial.token_type

類型

type: ProviderType;

此帳戶的供應商類型

userId?

optional userId: string;

此帳戶所屬的使用者 ID

參見

https://authjs.dev.org.tw/reference/core/adapters#adapteruser


DefaultSession

擴展自

屬性

expires

expires: string;

user?

optional user: User;

個人資料

從您的 OAuth 供應商返回的使用者資訊。

參見

https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims

可索引

[claim: string]: unknown

屬性

address?

optional address: null | {
  country: null | string;
  formatted: null | string;
  locality: null | string;
  postal_code: null | string;
  region: null | string;
  street_address: null | string;
};

birthdate?

optional birthdate: null | string;

email?

optional email: null | string;

email_verified?

optional email_verified: null | boolean;

family_name?

optional family_name: null | string;

gender?

optional gender: null | string;

given_name?

optional given_name: null | string;

id?

optional id: null | string;

locale?

optional locale: null | string;

middle_name?

optional middle_name: null | string;

name?

optional name: null | string;

nickname?

optional nickname: null | string;

phone_number?

optional phone_number: null | string;

picture?

optional picture: any;

preferred_username?

optional preferred_username: null | string;

profile?

optional profile: null | string;

sub?

optional sub: null | string;

updated_at?

optional updated_at: null | string | number | Date;

website?

optional website: null | string;

zoneinfo?

optional zoneinfo: null | string;

會期

已登入使用者的活動會期。

擴展自

屬性

expires

expires: string;
繼承自

DefaultSession.expires

user?

optional user: User;
繼承自

DefaultSession.user


使用者

OAuth 提供者的 profile 回呼中傳回的物件形狀,可在 jwtsession 回呼中取得,或是當使用資料庫時,在 session 回呼的第二個參數中取得。

擴展自

屬性

email?

optional email: null | string;

id?

optional id: string;

image?

optional image: null | string;

name?

optional name: null | string;

customFetch

const customFetch: unique symbol;
🚫

此選項允許您覆寫提供者用來直接向提供者的 OAuth 端點發出請求的預設 fetch 函數。不正確地使用可能會造成安全隱患。

它可以被用來支援企業代理伺服器、自訂 fetch 函式庫、快取探索端點、為測試新增模擬資料、記錄、為不符合規範的提供者設定自訂標頭/參數等等。

範例

import { Auth, customFetch } from "@auth/core"
import GitHub from "@auth/core/providers/github"
 
const dispatcher = new ProxyAgent("my.proxy.server")
function proxy(...args: Parameters<typeof fetch>): ReturnType<typeof fetch> {
  return undici(args[0], { ...(args[1] ?? {}), dispatcher })
}
 
const response = await Auth(request, {
  providers: [GitHub({ [customFetch]: proxy })]
})

請參閱


SvelteKitAuth()

SvelteKitAuth(config): {
  handle: Handle;
  signIn: Action;
  signOut: Action;
}

@auth/sveltekit 的主要進入點

參數

參數類型
configSvelteKitAuthConfig | (event) => PromiseLike<SvelteKitAuthConfig>

回傳值

{
  handle: Handle;
  signIn: Action;
  signOut: Action;
}

handle

handle: Handle;

signIn

signIn: Action;

signOut

signOut: Action;

請參閱

https://sveltekit.authjs.dev

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