跳至内容
从 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

除非您覆盖 SvelteKitAuthConfig.basePath,否则 提供者 使用的回调 URL 必须设置为以下内容。

[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>

管理会话

上面的示例检查了在 $page.data.session 中可用的会话,但是我们需要在某处设置它。如果您希望此数据可用于所有路由,则可以将其添加到 src/routes/+layout.server.ts 中。以下代码在 $page 存储中设置会话数据,使其可用于所有路由。

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 并从那里获取会话,但是即使您没有在根 +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的情况下使用存储。如果不这样做,可能会导致用户在+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 中的操作和 API 路由。
  • 组件之间没有代码重复。
  • 非常容易修改。

通过 URI 处理授权的方法是覆盖您的处理挂钩。处理挂钩,由您在src/auth.ts中的SvelteKitAuth返回,是一个旨在接收发送到您的 SvelteKit Web 应用程序的所有请求的函数。您应该从src/auth.ts导出它,并将其导入到您的src/hooks.server.ts中。为了在您的hooks.server.ts中使用多个处理程序,我们可以使用 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 的处理挂钩和序列的信息这里

现在,/authenticated下的任何路由都将被处理挂钩透明地保护。您可以向序列添加更多类似中间件的函数,并在该文件中实现更复杂的授权业务逻辑。如果需要保护特定页面,并且通过 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.node.org.cn/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. 用户被重定向到登录页面,URL 中包含 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

kind

static kind: string;
继承自

SignInError.kind

prepareStackTrace()?

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

用于格式化堆栈跟踪的可选覆盖。

参见

https://v8.node.org.cn/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.oauth.ac.cn/reference/core/providers 查看完整列表

providerAccountId

providerAccountId: string;

此值取决于用于创建账户的提供者类型。

  • oauth/oidc:OAuth 账户的 ID,从 profile() 回调返回。
  • 电子邮件:用户的电子邮件地址。
  • 凭据:从 authorize() 回调返回的 id

refresh_token?

optional readonly refresh_token: string;
继承自

Partial.refresh_token

范围?

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.oauth.ac.cn/reference/core/adapters#adapteruser


DefaultSession

扩展自

属性

过期时间

expires: string;

用户?

optional user: User;

个人资料

从您的 OAuth 提供者返回的用户信息。

参见

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

可索引

[claim: string]: unknown

属性

地址?

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

出生日期?

optional birthdate: null | string;

电子邮件?

optional email: null | string;

电子邮件已验证?

optional email_verified: null | boolean;

姓氏?

optional family_name: null | string;

性别?

optional gender: null | string;

名字?

optional given_name: null | string;

ID?

optional id: null | string;

区域设置?

optional locale: null | string;

中间名?

optional middle_name: null | string;

姓名?

optional name: null | string;

昵称?

optional nickname: null | string;

电话号码?

optional phone_number: null | string;

图片?

optional picture: any;

首选用户名?

optional preferred_username: null | string;

个人资料?

optional profile: null | string;

子?

optional sub: null | string;

更新时间?

optional updated_at: null | string | number | Date;

网站?

optional website: null | string;

时区信息?

optional zoneinfo: null | string;

会话

登录用户的活动会话。

扩展

属性

过期时间

expires: string;
继承自

DefaultSession.expires

用户?

optional user: User;
继承自

DefaultSession.user


用户

OAuth 提供者在 profile 回调中返回的对象的形状,在 jwtsession 回调中可用,或者在使用数据库时,session 回调的第二个参数。

扩展自

属性

电子邮件?

optional email: null | string;

ID?

optional id: string;

图片?

optional image: null | string;

姓名?

optional name: null | string;

自定义Fetch

const customFetch: unique symbol;
🚫

此选项允许您覆盖提供者使用的默认 fetch 函数,以直接向提供者的 OAuth 端点发出请求。使用不当会导致安全隐患。

它可用于支持公司代理、自定义提取库、缓存发现端点,添加用于测试、日志记录的模拟,为不符合规范的提供者设置自定义标头/参数等。

示例

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 的主要入口点

参数

参数类型
配置SvelteKitAuthConfig | (event) => PromiseLike<SvelteKitAuthConfig>

返回值

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

处理

handle: Handle;

登录

signIn: Action;

注销

signOut: Action;

参见

https://sveltekit.authjs.dev

Auth.js © Balázs Orbán 和团队 -2024