Nuxt 集成
将 Better Auth 集成到 Nuxt。
在开始之前,请确保你已经配置了 Better Auth 实例。如果还没有,查看 安装指南。
挂载处理器
将 Better Auth 处理器挂载到一个 catch-all Nitro 路由。创建文件 server/api/auth/[...all].ts:
import { auth } from "~~/lib/auth"; // 导入你的 auth 配置
export default defineEventHandler((event) => {
return auth.handler(toWebRequest(event));
});你可以在 Better Auth 配置中更改挂载路径,但建议保持为 /api/auth/[...all]。
创建客户端
使用 better-auth/vue 创建 auth 客户端,这样 useSession 会返回 Vue refs:
import { createAuthClient } from "better-auth/vue";
export const authClient = createAuthClient();
export const { signIn, signUp, signOut, useSession } = authClient;使用会话
在页面的 setup() 中使用 authClient.useSession(useFetch),即可在服务端加载会话并在客户端补水。传入 Nuxt 的 useFetch,这样请求会携带传入的 cookies,并且 payload 会在补水期间复用:
<script setup lang="ts">
import { authClient } from "~~/lib/auth-client";
const { data: session } = await authClient.useSession(useFetch);
</script>
<template>
<div v-if="session">
<p>欢迎,{{ session.user.name }}</p>
<button @click="authClient.signOut()">退出登录</button>
</div>
<button v-else @click="authClient.signIn.social({ provider: 'github' })">
使用 GitHub 继续
</button>
</template>对于像弹出层或菜单这类仅在客户端使用的组件,直接调用 authClient.useSession(),不要传参数。它会返回一个响应式 ref,并在登录和退出时自动更新。
保护页面
创建一个具名路由中间件,并通过 definePageMeta 将页面关联到该中间件:
import { authClient } from "~~/lib/auth-client";
export default defineNuxtRouteMiddleware(async (to) => {
const { data: session } = await authClient.useSession(useFetch);
if (!session.value) {
return navigateTo({ path: "/login", query: { redirect: to.fullPath } });
}
});<script setup lang="ts">
definePageMeta({ middleware: "auth" });
</script>将文件重命名为 app/middleware/auth.global.ts,即可使其在每个路由上运行。务必对 navigateTo(...) 调用使用 return,否则它不会生效。
保护服务端路由
使用传入的 event.headers 调用 auth.api.getSession,并用 createError 对路由进行保护:
import { auth } from "~~/lib/auth";
export default defineEventHandler(async (event) => {
const session = await auth.api.getSession({ headers: event.headers });
if (!session?.user) {
throw createError({ statusCode: 401, statusMessage: "未授权" });
}
return { user: session.user };
});如果你需要在很多路由中复用这段逻辑,可以把检查提取到你自己的 server/utils/ 辅助函数中。
在 SSR 期间使用客户端
除了 useSession(useFetch) 之外,authClient 的操作默认不会在 SSR 期间转发 cookies,因此会返回未认证状态。处理方式有两种:
方案 A:仅在客户端调用。 使用 <ClientOnly> 包裹消费者组件,或者通过 import.meta.client 做条件判断:
<script setup lang="ts">
import { authClient } from "~~/lib/auth-client";
const accounts = ref<Awaited<ReturnType<typeof authClient.listAccounts>>["data"]>();
onMounted(async () => {
const { data } = await authClient.listAccounts();
accounts.value = data;
});
</script>方案 B:创建一个按请求作用域的客户端,在 SSR 期间转发 cookies。 添加一个 useAuth 可组合函数,并与 useAsyncData 结合使用:
import { createAuthClient } from "better-auth/vue";
export function useAuth() {
const url = useRequestURL();
const headers = import.meta.server ? useRequestHeaders(["cookie"]) : undefined;
return createAuthClient({
baseURL: url.origin,
fetchOptions: { headers },
});
}<script setup lang="ts">
const { data: accounts } = await useAsyncData("accounts", () =>
useAuth().listAccounts().then((res) => res.data),
);
</script>与 Nuxt 层复用
当你想在多个 Nuxt 应用之间复用同一套 auth 配置时(例如一个营销站和一个仪表盘),可以将 lib/auth.ts、server/、app/middleware/ 和 app/composables/ 提取到一个 Nuxt 层 中,并在每个应用里继承它:
export default defineNuxtConfig({
extends: ["./layers/auth"],
});