Supabase会话认证与RLS疑问:跨端数据访问原理解析
我正在使用Supabase,重点研究其认证/会话管理机制。搭建了一个简单Node应用,包含signInWithPassword登录功能与getClients接口。
为clients表设置的SELECT策略如下:
alter policy "Enable read access for all users" on "public"."clients" to authenticated using ( true );
Node端signInWithPassword实现:
export const loginRepository = async (email: string, password: string) => { const { data, error } = await supabase.auth.signInWithPassword({ email, password, }); if (error) throw new Error(error.message); return data; };
getClients实现:
export const getClientsRepository = async () => { const { data, error } = await supabase.from("clients").select(); if (error) throw new Error(error.message); return data; };
clients表仅含id、name、surname、email、phone number字段,用于测试。
我发现通过Postman调用signInWithPassword登录后,可在浏览器、Postman等任意端获取数据。无法理解背后机制:Supabase如何识别用户?该过程是如何管理的?
根据文档,anon或publishable key用于认证应用而非用户,我使用了publishable key,换成anon key也有相同现象,希望有人能解释原理。
1. Supabase识别用户的核心:会话令牌
调用signInWithPassword登录成功后,Supabase会返回包含access_token、refresh_token和session对象的响应。其中access_token是JWT令牌,内置用户唯一标识(user_id)、角色等核心信息。
后续调用getClients这类数据接口时,Supabase JS SDK会自动将当前会话的access_token附加到请求的Authorization头(格式为Bearer <access_token>)。底层PostgREST服务会验证这个令牌:
- 检查令牌是否过期
- 验证签名合法性(确保是Supabase签发)
- 解析出用户身份与角色
只要令牌验证通过,请求就会被判定为来自authenticated角色的用户,符合你设置的RLS策略(允许所有authenticated用户读取),因此能获取数据。
2. Anon/Publishable Key的作用
这两个Key是应用级身份凭证,仅用于验证请求是否来自你的合法应用,和用户身份无关:
- Anon Key:供未登录的匿名用户使用
- Publishable Key:功能和Anon Key一致,是为前端场景安全命名的,权限上无区别
不管用哪个Key,只要请求携带合法的用户会话令牌,PostgREST都会优先以令牌中的用户身份判定权限,所以换Key后现象一致。
3. 跨端能获取数据的原因
在Postman登录后拿到的access_token,可以手动添加到其他端的请求头中;如果是Node服务里的单例Supabase客户端,登录后会话会被SDK自动存在内存,后续调用getClients时自动带上令牌。
浏览器环境下,Supabase SDK会把会话令牌存在localStorage,同一域名下的请求都会自动读取并携带令牌,这也是跨标签页能共享会话的原因。
4. 会话管理完整流程
- 用户登录:调用
signInWithPassword,Supabase Auth服务验证邮箱密码,签发access_token和refresh_token - 会话存储:SDK自动存储会话(Node端存内存,浏览器端存
localStorage) - 请求携带令牌:后续数据请求自动附加
Authorization头 - 令牌验证:PostgREST验证令牌,确认用户身份和角色
- RLS策略校验:根据用户角色和表策略,决定是否允许访问
内容的提问来源于stack exchange,提问作者Ncls7523

