@auth/sveltekit
@auth/sveltekit
目前处于实验阶段。API *可能* 会发生变化。
SvelteKit Auth 是 Auth.js 的官方 SvelteKit 集成。它提供了一种简单的方法,只需几行代码即可将身份验证添加到您的 SvelteKit 应用程序中。
安装
npm install @auth/sveltekit
用法
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 等平台时,这特别有用。
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
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
提供的开箱即用的组件 - 它们处理登录/登出流程,可以用作起点,也可以根据您的组件进行自定义。这是一个使用 SignIn
和 SignOut
组件通过 SvelteKit 的服务器端表单操作进行登录和登出的示例。您需要两件事才能使它工作
- 在您的 SvelteKit 应用程序前端使用这些组件
- 在
/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
中定义文件
import { signIn } from "../../auth"
import type { Actions } from "./$types"
export const actions: Actions = { default: signIn }
import { signOut } from "../../auth"
import type { Actions } from "./$types"
export const actions: Actions = { default: signOut }
这些路由可以通过各自组件上的 signInPage
和 signOutPage
属性进行自定义。
客户端
我们还从 @auth/sveltekit/client
中导出两个方法,以便执行客户端登录和登出操作。
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
来按顺序执行它们。
import { SvelteKitAuth } from '@auth/sveltekit';
import GitHub from '@auth/sveltekit/providers/github';
export const { handle, signIn, signOut } = SvelteKitAuth({
providers: [GitHub]
}),
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
AuthError
所有 Auth.js 错误的基本错误类。它经过优化,可以通过logger.error
选项以格式良好的方式打印在服务器日志中。
扩展
构造函数
new AuthError(message, errorOptions)
new AuthError(message?, errorOptions?): AuthError
参数
参数 | 类型 |
---|---|
message ? | string | ErrorOptions |
errorOptions ? | ErrorOptions |
返回
覆盖
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
参数
参数 | 类型 |
---|---|
err | Error |
stackTraces | CallSite [] |
返回
any
继承自
Error.prepareStackTrace
stackTraceLimit
static stackTraceLimit: number;
继承自
Error.stackTraceLimit
方法
captureStackTrace()
static captureStackTrace(targetObject, constructorOpt?): void
在目标对象上创建 .stack 属性。
参数
参数 | 类型 |
---|---|
targetObject | object |
constructorOpt ? | Function |
返回
void
继承自
Error.captureStackTrace
CredentialsSignin
可以从 Credentials 提供程序的 authorize
回调中抛出。当 authorize
回调中发生错误时,会发生两件事。
- 用户被重定向到登录页面,URL 中包含
error=CredentialsSignin&code=credentials
。code
是可配置的。 - 如果您在服务器端处理表单操作的框架中抛出此错误,则会抛出此错误,而不是重定向用户,因此您需要处理。
扩展
构造函数
new CredentialsSignin(message, errorOptions)
new CredentialsSignin(message?, errorOptions?): CredentialsSignin
参数
参数 | 类型 |
---|---|
message ? | string | ErrorOptions |
errorOptions ? | ErrorOptions |
返回
继承自
属性
cause?
optional cause: Record<string, unknown> & {
err: Error;
};
类型声明
err?
optional err: Error;
继承自
code
code: string;
在重定向 URL 的 code
查询参数中设置的错误代码。
⚠ 注意:此属性将包含在 URL 中,因此请确保它不会暗示敏感错误。
如果需要调试,完整错误始终记录在服务器上。
通常,我们不建议具体提示用户是否输入了错误的用户名或密码,而是尝试使用“无效凭据”之类的提示。
message
message: string;
继承自
name
name: string;
继承自
stack?
optional stack: string;
继承自
type
type: ErrorType;
错误类型。用于在日志中识别错误。
继承自
kind
static kind: string;
继承自
prepareStackTrace()?
static optional prepareStackTrace: (err, stackTraces) => any;
用于格式化堆栈跟踪的可选覆盖。
参见
https://v8.node.org.cn/docs/stack-trace-api#customizing-stack-traces
参数
参数 | 类型 |
---|---|
err | Error |
stackTraces | CallSite [] |
返回值
any
继承自
stackTraceLimit
static stackTraceLimit: number;
继承自
类型
static type: string;
方法
captureStackTrace()
static captureStackTrace(targetObject, constructorOpt?): void
在目标对象上创建 .stack 属性。
参数
参数 | 类型 |
---|---|
targetObject | object |
constructorOpt ? | Function |
返回值
void
继承自
账户
通常包含有关使用提供者的信息,并且还扩展了 TokenSet
,它是 OAuth 提供者返回的不同令牌。
扩展
Partial
<TokenEndpointResponse
>
属性
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。
参见
- https://authjs.oauth.ac.cn/guides/refresh-token-rotation#database-strategy
- https://www.rfc-editor.org/rfc/rfc6749#section-5.1
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;
继承自
用户?
optional user: User;
继承自
用户
OAuth 提供者在 profile
回调中返回的对象的形状,在 jwt
和 session
回调中可用,或者在使用数据库时,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 })]
})
参见
- https://undici.nodejs.org/#/docs/api/ProxyAgent?id=example-basic-proxy-request-with-local-agent-dispatcher
- https://authjs.oauth.ac.cn/guides/corporate-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;