从 Supabase Auth 迁移至 Better Auth
在本指南中,我们将逐步介绍如何将项目从 Supabase Auth 迁移到 Better Auth。
此迁移将使所有活动会话失效。虽然本指南目前未涵盖双因素认证(2FA)或行级安全(RLS)配置的迁移,但通过额外步骤这两者都是可以实现的。
开始之前
在开始迁移过程之前,请先在您的项目中设置 Better Auth。请按照安装指南开始操作。
连接到您的数据库
您需要连接到数据库以迁移用户和账户。从您的 Supabase 项目中复制 DATABASE_URL
,并用它来连接数据库。在此示例中,我们需要安装 pg
来连接数据库。
npm install pg
然后您可以使用以下代码连接到数据库。
import { Pool } from "pg";
export const auth = betterAuth({
database: new Pool({
connectionString: process.env.DATABASE_URL
}),
})
启用邮箱和密码认证(可选)
在您的认证配置中启用邮箱和密码认证。
import { admin, anonymous } from "better-auth/plugins";
export const auth = betterAuth({
database: new Pool({
connectionString: process.env.DATABASE_URL
}),
emailVerification: {
sendEmailVerification: async(user)=>{
// 发送邮箱验证邮件
// 在此处实现您自己的逻辑
}
},
emailAndPassword: {
enabled: true,
}
})
设置社交登录提供商(可选)
在您的认证配置中添加已在 Supabase 项目中启用的社交登录提供商。
import { admin, anonymous } from "better-auth/plugins";
export const auth = betterAuth({
database: new Pool({
connectionString: process.env.DATABASE_URL
}),
emailAndPassword: {
enabled: true,
},
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
}
}
})
添加管理员和匿名插件(可选)
import { admin, anonymous } from "better-auth/plugins";
export const auth = betterAuth({
database: new Pool({
connectionString: process.env.DATABASE_URL
}),
emailAndPassword: {
enabled: true,
},
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
}
},
plugins: [admin(), anonymous()],
})
复制迁移脚本
现在我们的数据库中已经有了必要的表,可以运行迁移脚本将用户和账户从 Supabase 迁移到 Better Auth。
首先在你的项目中创建一个 .ts
文件。
touch migration.ts
然后将以下代码复制粘贴到文件中。
import { Pool } from "pg";
import { auth } from "./auth";
import { User as SupabaseUser } from "@supabase/supabase-js";
type User = SupabaseUser & {
is_super_admin: boolean;
raw_user_meta_data: {
avatar_url: string;
};
encrypted_password: string;
email_confirmed_at: string;
created_at: string;
updated_at: string;
is_anonymous: boolean;
identities: {
provider: string;
identity_data: {
sub: string;
email: string;
};
created_at: string;
updated_at: string;
};
};
const migrateFromSupabase = async () => {
const ctx = await auth.$context;
const db = ctx.options.database as Pool;
const users = await db
.query(`
SELECT
u.*,
COALESCE(
json_agg(
i.* ORDER BY i.id
) FILTER (WHERE i.id IS NOT NULL),
'[]'::json
) as identities
FROM auth.users u
LEFT JOIN auth.identities i ON u.id = i.user_id
GROUP BY u.id
`)
.then((res) => res.rows as User[]);
for (const user of users) {
if (!user.email) {
continue;
}
await ctx.adapter
.create({
model: "user",
data: {
id: user.id,
email: user.email,
name: user.email,
role: user.is_super_admin ? "admin" : user.role,
emailVerified: !!user.email_confirmed_at,
image: user.raw_user_meta_data.avatar_url,
createdAt: new Date(user.created_at),
updatedAt: new Date(user.updated_at),
isAnonymous: user.is_anonymous,
},
})
.catch(() => {});
for (const identity of user.identities) {
const existingAccounts = await ctx.internalAdapter.findAccounts(user.id);
if (identity.provider === "email") {
const hasCredential = existingAccounts.find(
(account) => account.providerId === "credential",
);
if (!hasCredential) {
await ctx.adapter
.create({
model: "account",
data: {
userId: user.id,
providerId: "credential",
accountId: user.id,
password: user.encrypted_password,
createdAt: new Date(user.created_at),
updatedAt: new Date(user.updated_at),
},
})
.catch(() => {});
}
}
const supportedProviders = Object.keys(ctx.options.socialProviders || {})
if (supportedProviders.includes(identity.provider)) {
const hasAccount = existingAccounts.find(
(account) => account.providerId === identity.provider,
);
if (!hasAccount) {
await ctx.adapter.create({
model: "account",
data: {
userId: user.id,
providerId: identity.provider,
accountId: identity.identity_data?.sub,
createdAt: new Date(identity.created_at ?? user.created_at),
updatedAt: new Date(identity.updated_at ?? user.updated_at),
},
});
}
}
}
}
};
migrateFromSupabase();
自定义迁移脚本(可选)
name
:迁移脚本默认使用用户的邮箱作为名称。如果您在数据库中有用户显示名称,可能需要自定义此项。socialProviderList
:迁移脚本将使用您在认证配置中启用的社交登录提供商。如果您有在认证配置中未启用的额外社交提供商,可能需要自定义此项。role
:如果您未使用admin
插件,请移除role
字段。isAnonymous
:如果您未使用anonymous
插件,请移除isAnonymous
字段。- 更新其他引用
users
表的表,以使用id
字段。
更新代码
将您的代码库从 Supabase 身份验证调用更新为 Better Auth API。
以下是 Supabase 身份验证 API 调用及其对应的 Better Auth 方法:
supabase.auth.signUp
->authClient.signUp.email
supabase.auth.signInWithPassword
->authClient.signIn.email
supabase.auth.signInWithOAuth
->authClient.signIn.social
supabase.auth.signInAnonymously
->authClient.signIn.anonymous
supabase.auth.signOut
->authClient.signOut
supabase.auth.getSession
->authClient.getSession
- 您也可以使用authClient.useSession
来获取响应式状态
了解更多:
中间件
要使用中间件保护路由,请参考 Next.js 中间件指南 或您所用框架的文档。
总结
恭喜!您已成功从 Supabase Auth 迁移到 Better Auth。
Better Auth 提供了更大的灵活性和更多功能——请务必探索文档以解锁其全部潜力。