匿名登录
创建并使用匿名用户进行 Supabase 认证
启用匿名登录 以构建应用程序,为用户提供经过身份验证的体验,而无需用户输入电子邮件地址、密码、使用 OAuth 提供商或提供任何其他个人身份信息(PII)。之后,当准备好时,用户可以将其账户关联到一个身份验证方法。
匿名用户与匿名密钥的区别
调用 signInAnonymously()
(匿名登录)会创建一个匿名用户。它就像一个永久用户,但如果用户退出登录、清除浏览数据或使用其他设备,则无法访问其账户。
与永久用户一样,当使用数据API访问您的项目时,将使用 authenticated
Postgres 角色。这些用户的 JWT(JSON Web Token)将包含一个 is_anonymous
声明,您可以使用它在 RLS(行级安全)策略中进行区分。
这与 anon
API 密钥不同,anon
API 密钥不会创建用户,并且可用于实现对数据库的公共访问,因为它使用 anonymous
Postgres 角色。
匿名登录可用于构建:
- 电子商务应用程序,例如结账前的购物车
- 无需收集个人信息的全功能演示
- 临时或一次性账户
在启用匿名登录之前,请检查您现有的 RLS(行级安全)策略。匿名用户使用 authenticated
角色。为了区分匿名用户和永久用户,您的策略需要检查用户 JWT 中的 is_anonymous
字段。
更多详情请参阅访问控制部分。
Next.js 中使用动态渲染
Supabase 团队收到了关于 Next.js 静态页面渲染导致用户元数据在不同匿名用户之间被缓存的报告。为了获得最佳用户体验,请使用动态页面渲染。
自托管和本地开发
对于自托管,您可以使用提供的文件和环境变量更新项目配置。更多详情请参阅本地开发文档。
匿名登录
调用 signInAnonymously()
方法:
1const { , } = await ..()
将匿名用户转换为永久用户
将匿名用户转换为永久用户需要将身份关联到该用户。这要求您在 Supabase 项目中启用手动关联。
关联电子邮件/电话身份
您可以使用 updateUser()
方法将电子邮件或电话身份关联到匿名用户。要为匿名用户添加密码,需要先验证用户的电子邮件或电话号码。
12345678910const { : , : } = await ..({ : 'valid.email@supabase.io',})// 通过点击电子邮件更改链接或输入发送到电子邮件地址的6位OTP来验证用户电子邮件// 用户验证成功后,更新密码const { : , : } = await ..({ : 'password',})
关联OAuth身份
您可以使用 linkIdentity()
方法将OAuth身份关联到匿名用户。
1const { , } = await ..({ : 'google' })
访问控制
匿名用户与永久用户一样,都承担 authenticated
角色。您可以使用行级安全(RLS)策略,通过检查 auth.jwt()
返回的 JWT 中 is_anonymous
声明来区分匿名用户和永久用户:
123456789create policy "Only permanent users can post to the news feed"on news_feed as restrictive for insertto authenticatedwith check ((select (auth.jwt()->>'is_anonymous')::boolean) is false );create policy "Anonymous and permanent users can view the news feed"on news_feed for selectto authenticatedusing ( true );
使用限制性策略
RLS 策略默认是许可性的,这意味着当应用多个策略时,它们会通过“OR”操作符进行组合。因此,构建限制性策略以确保在与其他策略组合时,对匿名用户的检查始终得到强制执行,这一点非常重要。
解决身份冲突
根据您的应用程序需求,当匿名用户转换为永久用户时,可能会出现数据冲突。例如,在电子商务应用程序中,匿名用户无需注册/登录即可将商品添加到购物车。当他们决定登录现有账户时,您需要决定如何解决购物车中的数据冲突:
- 用现有账户中的商品覆盖购物车中的商品
- 用匿名用户购物车中的商品覆盖现有账户中的商品
- 合并购物车中的商品
将匿名用户关联到现有账户
在某些情况下,您可能需要将匿名用户关联到现有账户,而不是创建一个新的永久账户。此过程需要手动处理潜在的冲突。以下是一个通用方法:
12345678910111213141516171819202122232425262728293031323334353637383940// 1. 匿名登录(假设用户已匿名登录)const { data: anonData, error: anonError } = await supabase.auth.getSession()// 2. 尝试使用现有邮箱更新用户const { data: updateData, error: updateError } = await supabase.auth.updateUser({ email: 'valid.email@supabase.io',})// 3. 处理错误(因为该邮箱属于现有用户)if (updateError) { console.log('此邮箱属于现有用户。请登录该账户。') // 4. 登录现有账户 const { data: { user: existingUser }, error: signInError, } = await supabase.auth.signInWithPassword({ email: 'valid.email@supabase.io', password: 'user_password', }) if (existingUser) { // 5. 重新分配与匿名用户关联的实体 // 此步骤将根据您的具体用例和数据模型而异 const { data: reassignData, error: reassignError } = await supabase .from('your_table') .update({ user_id: existingUser.id }) .eq('user_id', anonData.session.user.id) // 6. 实现您选择的冲突解决策略 // 这可能涉及数据合并、覆盖或其他自定义逻辑 await resolveDataConflicts(anonData.session.user.id, existingUser.id) }}// 辅助函数,用于解决数据冲突(根据您的策略实现)async function resolveDataConflicts(anonymousUserId, existingUserId) { // 在此处实现您的冲突解决逻辑 // 这可能涉及忽略匿名用户的元数据、覆盖现有用户的元数据,或合并匿名用户和现有用户的数据。}
滥用防护与速率限制
由于匿名用户存储在您的数据库中,恶意行为者可能会滥用该端点,导致您的数据库大小急剧增加。强烈建议启用隐形验证码或 Cloudflare Turnstile,以防止匿名登录被滥用。系统会强制执行每小时30次请求的基于IP的速率限制,您可以在控制台中修改此设置。您可以在此处查看完整的速率限制列表。
自动清理
目前不支持匿名用户的自动清理功能。相反,您可以通过运行以下SQL从项目中删除匿名用户:
123-- 删除30天前创建的匿名用户delete from auth.userswhere is_anonymous is true and created_at < now() - interval '30 days';