Menu

Nexty 授权功能使用指南

  • 核心库: Better-auth
  • 数据库: drizzle 适配,表:usersessionaccountverification
  • 支持的功能:
    • 登录方式: 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_IDGOOGLE_CLIENT_SECRET
    • GitHub: NEXT_PUBLIC_GITHUB_CLIENT_IDGITHUB_CLIENT_SECRET
  • 人机验证(Turnstile):
    • NEXT_PUBLIC_TURNSTILE_SITE_KEY(前端)
    • TURNSTILE_SECRET_KEY(服务端)

可选:调整 trustedOriginslib/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) => {/* 错误提示 */},
  }
);
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
    • 发送欢迎邮件
  • 你可在 lib/auth/index.ts 中继续扩展这些钩子(如风控、审计日志等)。

常见问题与排错

  • 登录后被重定向回错误域名
    • 设置 BETTER_AUTH_URLNEXT_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.tsgetSessionisAdmin
  • 路由守卫组件:components/auth/AuthGuard.tsx
  • 登录表单示例:components/auth/LoginForm.tsx
  • One Tap:components/auth/GoogleOneTap.tsx
  • 用户菜单/退出:components/header/UserInfo.tsx