上次登录方式
跟踪并显示用户最后使用的身份验证方式
上次登录方式插件用于跟踪用户最近一次使用的身份验证方式(邮箱、OAuth 提供商等)。这使您能够在登录页面上显示有用的指示标志,例如“上次使用 Google 登录”,或根据用户偏好优先显示某些登录方式。
安装
在你的 auth 配置中添加插件
import { betterAuth } from "better-auth"
import { lastLoginMethod } from "better-auth/plugins"
export const auth = betterAuth({
// ... 其他配置选项
plugins: [
lastLoginMethod()
]
})在你的 auth 客户端中添加客户端插件
import { createAuthClient } from "better-auth/client"
import { lastLoginMethodClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [
lastLoginMethodClient()
]
})使用方法
安装后,插件会自动跟踪用户最后一次使用的身份验证方式。你可以在应用程序中检索并显示该信息。
获取最后使用的方式
客户端插件提供了多个方法来操作最后登录的方式:
import { authClient } from "@/lib/auth-client"
// 获取最后使用的登录方式
const lastMethod = authClient.getLastUsedLoginMethod()
console.log(lastMethod) // "google", "email", "github" 等等
// 检查某种方式是否为最后使用
const wasGoogle = authClient.isLastUsedLoginMethod("google")
// 清除存储的登录方式
authClient.clearLastUsedLoginMethod()UI 集成示例
下面展示如何使用该插件增强登录页面:
import { authClient } from "@/lib/auth-client"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
export function SignInPage() {
const lastMethod = authClient.getLastUsedLoginMethod()
return (
<div className="space-y-4">
<h1>登录</h1>
{/* 邮箱登录 */}
<div className="relative">
<Button
onClick={() => authClient.signIn.email({...})}
variant={lastMethod === "email" ? "default" : "outline"}
className="w-full"
>
使用邮箱登录
{lastMethod === "email" && (
<Badge className="ml-2">上次使用</Badge>
)}
</Button>
</div>
{/* OAuth 提供商 */}
<div className="relative">
<Button
onClick={() => authClient.signIn.social({ provider: "google" })}
variant={lastMethod === "google" ? "default" : "outline"}
className="w-full"
>
使用 Google 登录
{lastMethod === "google" && (
<Badge className="ml-2">上次使用</Badge>
)}
</Button>
</div>
<div className="relative">
<Button
onClick={() => authClient.signIn.social({ provider: "github" })}
variant={lastMethod === "github" ? "default" : "outline"}
className="w-full"
>
使用 GitHub 登录
{lastMethod === "github" && (
<Badge className="ml-2">上次使用</Badge>
)}
</Button>
</div>
</div>
)
}数据库持久化
默认情况下,最后登录方式仅存储在 cookie 中。若需更持久的跟踪和分析,可以启用数据库存储。
启用数据库存储
在插件配置中将 storeInDatabase 设置为 true:
import { betterAuth } from "better-auth"
import { lastLoginMethod } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
lastLoginMethod({
storeInDatabase: true
})
]
})访问数据库字段
启用数据库存储后,lastLoginMethod 字段将出现在用户对象中:
import { auth } from "@/lib/auth"
// 服务器端访问
const session = await auth.api.getSession({ headers })
console.log(session?.user.lastLoginMethod) // "google", "email" 等等
// 客户端通过 session 访问
const { data: session } = authClient.useSession()
console.log(session?.user.lastLoginMethod)数据库模式
启用 storeInDatabase 后,插件会在 user 表中添加如下字段:
表:user
自定义模式配置
你可以自定义数据库字段名:
import { betterAuth } from "better-auth"
import { lastLoginMethod } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
lastLoginMethod({
storeInDatabase: true,
schema: {
user: {
lastLoginMethod: "last_auth_method" // 自定义字段名
}
}
})
]
})配置选项
上次登录方式插件接受以下选项:
服务端选项
import { betterAuth } from "better-auth"
import { lastLoginMethod } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
lastLoginMethod({
// Cookie 配置
cookieName: "better-auth.last_used_login_method", // 默认: "better-auth.last_used_login_method"
maxAge: 60 * 60 * 24 * 30, // 默认: 30 天,单位秒
// 数据库存储
storeInDatabase: false, // 默认: false
// 自定义方式解析
customResolveMethod: (ctx) => {
// 自定义逻辑决定登录方式
if (ctx.path === "/oauth/callback/custom-provider") {
return "custom-provider"
}
// 返回 null 使用默认解析
return null
},
// 模式定制 (启用 storeInDatabase 时)
schema: {
user: {
lastLoginMethod: "custom_field_name"
}
}
})
]
})cookieName: string
- 用于存储最后登录方式的 cookie 名称
- 默认:
"better-auth.last_used_login_method" - 注意:该 cookie 设置为
httpOnly: false,允许客户端 JavaScript 访问,用于 UI 功能
maxAge: number
- cookie 过期时间,单位为秒
- 默认:
2592000(30 天)
storeInDatabase: boolean
- 是否将最后登录方式存储到数据库中
- 默认:
false - 启用后会在用户表中添加
lastLoginMethod字段
customResolveMethod: (ctx: GenericEndpointContext) => string | null
- 自定义函数根据请求上下文判断登录方式
- 返回
null则使用默认解析逻辑 - 适用于自定义 OAuth 提供商或身份验证流程
schema: object
- 在启用
storeInDatabase时自定义数据库字段名映射 - 允许将
lastLoginMethod字段映射到自定义列名
客户端选项
import { createAuthClient } from "better-auth/client"
import { lastLoginMethodClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [
lastLoginMethodClient({
cookieName: "better-auth.last_used_login_method" // 默认: "better-auth.last_used_login_method"
})
]
})cookieName: string
- 用于读取最后登录方式的 cookie 名称
- 必须和服务端的
cookieName配置一致 - 默认:
"better-auth.last_used_login_method"
默认方式解析
插件默认跟踪以下身份验证方式:
- 邮箱身份验证:
"email" - OAuth 提供商:提供商 ID(例如
"google","github","discord") - OAuth2 回调:从 URL 路径提取提供商 ID
- 注册方式:和登录方式相同的方式跟踪
插件自动检测以下端点的方式:
/callback/:id- OAuth 回调,带有提供商 ID/oauth2/callback/:id- OAuth2 回调,带有提供商 ID/sign-in/email- 邮箱登录/sign-up/email- 邮箱注册
跨域支持
插件自动继承 Better Auth 集中 cookie 系统的 cookie 设置,解决了最后登录方式无法跨越以下情况持久化的问题:
- 跨子域部署:
auth.example.com→app.example.com - 跨源部署:
api.company.com→app.different.com
当你在 Better Auth 配置中启用 crossSubDomainCookies 或 crossOriginCookies,插件会自动使用与会话 cookie 相同的域、secure 和 sameSite 设置,确保应用中的一致行为。
高级示例
自定义提供商跟踪
如果你有自定义的 OAuth 提供商或身份验证方式,可以使用 customResolveMethod 选项:
import { betterAuth } from "better-auth"
import { lastLoginMethod } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
lastLoginMethod({
customResolveMethod: (ctx) => {
// 跟踪自定义 SAML 提供商
if (ctx.path === "/saml/callback") {
return "saml"
}
// 跟踪 magic link 验证
if (ctx.path === "/magic-link/verify") {
return "magic-link"
}
// 跟踪手机身份验证
if (ctx.path === "/sign-in/phone") {
return "phone"
}
// 返回 null 使用默认逻辑
return null
}
})
]
})与 Expo 一起使用
使用 Better Auth 配合 Expo 时,请确保从 @better-auth/expo/plugins 而非 better-auth/plugins/client 导入客户端插件。这确保最后登录方式能正确存储到配置的存储中。
import { createAuthClient } from "better-auth/react"
import { expoClient } from "@better-auth/expo"
import { lastLoginMethodClient } from "@better-auth/expo/plugins"
import * as SecureStore from "expo-secure-store"
export const authClient = createAuthClient({
plugins: [
expoClient({
scheme: "myapp",
storagePrefix: "myapp",
storage: SecureStore,
}),
lastLoginMethodClient({
storagePrefix: "myapp",
storage: SecureStorage,
})
]
})对于仅使用 Expo 的应用,不需要浏览器支持时,可以只使用客户端插件,省略服务端插件。