Nexty 授权功能使用指南
- 核心库: Better-auth
- 数据库:
drizzle
适配,表:user
、session
、account
、verification
- 支持的功能:
- 登录方式: Google、GitHub、邮箱魔法链接(Magic Link)、Google One Tap
- 安全增强: Cloudflare Turnstile 验证码
- 邮件服务: 新用户注册发送欢迎邮件
- 角色与访问控制:
user.role
(默认user
,支持admin
),封装了getSession()
、isAdmin()
与AuthGuard
- 记录用户来源: 根据用户访问链接的参数,记录用户来源
- 屏蔽用户: 管理员可轻松屏蔽风险用户,保护系统安全
- 记录用户登录方式: 在本地记录用户上一次登录方式,让用户更快完成登录
必要环境变量
- 基础:
NEXT_PUBLIC_SITE_URL
(用于 auth 回调基准域名)BETTER_AUTH_SECRET
(服务端密钥)
- 社交登录:
- Google:
NEXT_PUBLIC_GOOGLE_CLIENT_ID
、GOOGLE_CLIENT_SECRET
- GitHub:
NEXT_PUBLIC_GITHUB_CLIENT_ID
、GITHUB_CLIENT_SECRET
- Google:
- 人机验证(Turnstile):
NEXT_PUBLIC_TURNSTILE_SITE_KEY
(前端)TURNSTILE_SECRET_KEY
(服务端)
可选:调整 trustedOrigins
(lib/auth/index.ts
)以匹配你的部署域名。
服务端用法
读取会话与保护接口
// 任意 Server Component / Route Handler / Server Action
import { getSession } from "@/lib/auth/server";
export async function SomeServerActions(req: Request) {
const session = await getSession()
const user = session?.user;
if (!user) return actionResponse.unauthorized();
// session.user: { id, email, role, ... }
return actionResponse.success({});
}
角色校验(管理员)
import { isAdmin } from "@/lib/auth/server";
export async function SomeAdminServerActions() {
if (!(await isAdmin())) return actionResponse.forbidden('Admin privileges required.')
// 管理员逻辑
}
页面级守卫(同步重定向)
// 组件:components/auth/AuthGuard.tsx 已封装
import { AuthGuard } from "@/components/auth/AuthGuard";
export default async function LoginRequiredLayout() {
return (
<AuthGuard>
{/* 仅登录用户可见的内容 */}
</AuthGuard>
);
}
// 组件:components/auth/AuthGuard.tsx 已封装
import { AuthGuard } from "@/components/auth/AuthGuard";
export default async function AdminLayout() {
return (
<AuthGuard role="admin">
{/* 仅管理员可见的内容 */}
</AuthGuard>
);
}
客户端用法
获取会话与登录状态
import { authClient } from "@/lib/auth/auth-client";
// React 客户端组件
const { data: session, isPending } = authClient.useSession();
社交登录(Google/GitHub)
await authClient.signIn.social(
{
provider: "google", // 或 "github"
callbackURL: window.location.origin, // 登录后回到哪里
errorCallbackURL: "/redirect-error",
},
{
onRequest: () => {/* loading UI */},
onSuccess: (ctx) => {/* 已登录 */},
onError: (ctx) => {/* 错误提示 */},
}
);
邮箱 Magic Link 登录(带 Turnstile 验证)
import { Turnstile } from "@marsidev/react-turnstile";
// 1) 前端获取 token
<Turnstile
siteKey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY!}
onSuccess={(token) => setCaptchaToken(token)}
/>
// 2) 调用 magic link 登录,携带验证码
await authClient.signIn.magicLink({
email, // 用户输入的邮箱
name: "optional",
callbackURL: window.location.origin,
errorCallbackURL: "/redirect-error",
fetchOptions: {
headers: { "x-captcha-response": captchaToken }, // 关键:传给服务端
},
});
Google One Tap(免输入账号密码)
import { authClient } from "@/lib/auth/auth-client";
await authClient.oneTap({
fetchOptions: {
onSuccess: () => window.location.reload(),
onError: (ctx) => console.error(ctx.error),
},
onPromptNotification: (note) => console.log(note),
});
退出登录
await authClient.signOut({
fetchOptions: {
onSuccess: () => router.refresh(),
},
});
最近一次使用的登录方式
const lastLogin = authClient.getLastUsedLoginMethod(); // "google" | "github" | "email" | undefined
角色与账号管理
用户表角色有:'user' | 'admin'
,默认新注册为 user
。
将某个用户提升管理员的方法:
打开数据库 user
表,找到你要设置为管理员的那个用户,将 role
设置为 admin
。

现在重新登录管理员账号,就可以看到管理员的目录了。

授权流里的业务钩子(已内置)
- 用户创建后(
databaseHooks.user.create.after
):- 从 Cookie
referral_source
读取渠道码并写入user.referral
- 发送欢迎邮件
- 从 Cookie
- 你可在
lib/auth/index.ts
中继续扩展这些钩子(如风控、审计日志等)。
常见问题与排错
- 登录后被重定向回错误域名
- 设置
BETTER_AUTH_URL
或NEXT_PUBLIC_SITE_URL
为正确站点地址。 - 若跨域回调,补充
trustedOrigins
。
- 设置
- Turnstile 验证失败
- 前端确保传递
x-captcha-response
头;后端TURNSTILE_SECRET_KEY
必填。
- 前端确保传递
- 社交登录报错
- 检查对应的
CLIENT_ID/SECRET
;在各平台控制台将回调域名/路径加入白名单。
- 检查对应的
- 获取会话为空
- 服务端必须通过
headers()
传递请求头,getSession()
已封装;确认 cookie 未被跨域或 SameSite 策略拦截。
- 服务端必须通过
参考文件
- 配置与插件:
lib/auth/index.ts
- 客户端 SDK:
lib/auth/auth-client.ts
- 服务端封装:
lib/auth/server.ts
(getSession
、isAdmin
) - 路由守卫组件:
components/auth/AuthGuard.tsx
- 登录表单示例:
components/auth/LoginForm.tsx
- One Tap:
components/auth/GoogleOneTap.tsx
- 用户菜单/退出:
components/header/UserInfo.tsx