前端React+Supabase Auth,后端Flask对接Supabase RLS存储权限问题
解决方案:Supabase Storage 上传时传递用户认证信息
你的核心问题是错误地将认证头放在了file_options参数中——这个参数是用来设置文件的元数据(比如MIME类型、自定义文件属性),而非HTTP请求头,所以Supabase无法识别该用户的认证状态。
下面提供两种可行的修正方案:
方案一:基于用户Token创建临时Supabase客户端
直接用前端传递的用户access token初始化一个临时Supabase客户端,该客户端发起的所有请求都会自动携带用户认证信息,完美适配RLS策略。
修改后的upload_file函数:
from supabase import create_client, Client # 全局变量:替换成你的Supabase项目URL和Anon密钥 SUPABASE_URL = "你的Supabase URL" SUPABASE_ANON_KEY = "你的Supabase Anon密钥" def upload_file(file_name, bucket, token): # 创建临时Supabase客户端 supabase: Client = create_client(SUPABASE_URL, SUPABASE_ANON_KEY) # 给客户端设置用户的认证Token supabase.postgrest.auth(token) # 同步给Storage模块设置认证头 supabase.storage._request.headers["Authorization"] = f"Bearer {token}" with open(file_name, "rb") as f: supabase.storage.from_(bucket).upload( file=f, path=file_name, file_options={ "content-type": "image/jpeg" }, )
方案二:手动调用底层API,自定义请求头
如果你不想创建新的客户端实例,可以直接调用Storage客户端的底层_request方法,手动构造上传请求并添加认证头:
def upload_file(file_name, bucket, token): storage_client = supabase.storage.from_(bucket) with open(file_name, "rb") as f: # 构造上传接口的路径 request_path = f"/object/{bucket}/{file_name}" # 发起PUT请求,携带认证头和文件数据 response = storage_client._request( method="PUT", path=request_path, headers={ "Authorization": f"Bearer {token}", "Content-Type": "image/jpeg" }, data=f ) # 检查响应状态,处理错误 if response.status_code not in (200, 201): raise Exception(f"上传失败:{response.text}")
额外注意事项
- RLS策略配置:确保你已经为Supabase Storage的
produtos桶配置了正确的RLS策略,比如允许认证用户上传/访问指定路径,示例策略:CREATE POLICY "认证用户可上传产品图片" ON storage.objects FOR INSERT WITH CHECK ( auth.role() = 'authenticated' AND bucket_id = 'produtos' AND owner = auth.uid() ); - Token验证:你的
verify_token函数必须使用Supabase项目的JWT秘钥(在项目设置→API→JWT Secret)来验证token的有效性,避免无效/过期token被使用。 - 文件路径优化:当前代码用原始文件名作为存储路径,建议结合
user_id或cdProduto构建更安全的路径(比如produtos/{user_id}/{cdProduto}/{nrImagem}.jpg),配合RLS策略进一步限制访问范围。
内容的提问来源于stack exchange,提问作者Augusto Peres
相关产品推荐
相关产品推荐

