首页
/ Supabase Studio Firebase Wrapper 指南:用 Postgres FDW 直接读取 Firebase Auth 用户与 Firestore 数据

Supabase Studio Firebase Wrapper 指南:用 Postgres FDW 直接读取 Firebase Auth 用户与 Firestore 数据

2026-09-06 14:49:45作者:殷蕙予

在 Supabase 生态中,Firebase 是一个常见的"外部数据源"——很多团队既有存量的 Firebase 项目(Auth 用户、Firestore 文档),又希望在新应用中使用 Postgres。本篇围绕 Studio 集成页中的 Firebase Wrapper 概览文档(overview.md)展开,讲清它的定位:一个基于 Postgres 外部数据包装器(Foreign Data Wrapper,FDW)的集成,让你在 Postgres 里直接查询 Firebase 数据。读完本文,你将掌握:Firebase Wrapper 支持的连接对象及其完整参数(默认值、加密策略)、对应的 SQL 创建方式、FDW 的安全边界,以及它与 Firebase 第三方登录、Firestore 数据迁移这两个相邻功能的区别。

Firebase Wrapper 是什么

原始概览文档只有三句话,但信息密度很高,它给出了两个关键定义:

Firebase is an app development platform built around non-relational technologies. The Firebase Wrapper supports connecting to below objects. The Firebase Wrapper is a foreign data wrapper which allows you to read data from Firebase within your Postgres database.

翻译过来即:Firebase 是围绕非关系型技术构建的应用开发平台,而 Firebase Wrapper 是一个外部数据包装器(FDW),让你可以在 Postgres 数据库内部读取 Firebase 的数据

FDW 是 Postgres 的核心能力:把外部系统里的数据映射成本地"外表"(foreign table),用标准 SQL 查询,但数据实际仍存放在远端。Supabase 将这一能力扩展成开放的 Wrappers 框架,Firebase Wrapper 就是其中一员。按该框架的概念体系:

  • Remote Server:你要访问的外部系统,这里是某个 Firebase 项目。同一个数据库里可以创建多个 Remote Server 连接不同的 Firebase 项目;
  • Foreign table:数据库中的一张表,映射到 Remote Server 里的某份数据(对应本文下面介绍的 Users 与 Firestore Collection 两类对象)。外表查询时数据不落库,始终从 Firebase 实时拉取;
  • ETL / QETL:你可以用 insert into ... select from <外表> 把 Firebase 数据导入本地表(批量 ETL,可配合 pg_cron 定时),也可以直接把外表当普通表 join 你的业务表做实时查询(QETL,即"按需查询")。

从源码结构看,概览文档本身只是 Studio 的一个静态展示条目,它由一个注册表按需加载:overviews.tsfirebase_wrapper 键对应一条动态 importloadIntegrationOverview(integrationId) 在用户打开 Integrations 页面的 Firebase 条目时才返回这段 Markdown 原文。该文件顶部的注释还解释了为何必须写成字符串字面量导入——webpack/turbopack 与 Vite/Rolldown 对模板字符串动态导入的处理不一致,动态写法会在 TanStack 构建中抛 Failed to resolve module specifier

Studio 中 Firebase Wrapper 的参数定义

概览文档说 "supports connecting to below objects"(支持连接以下对象),具体对象、参数、默认值并不在 Markdown 里,而是定义在 Studio 的常量 Wrappers.constants.ts 中。该条目声明了完整的技术指纹:

字段 含义
name firebase_wrapper 集成 id(即 static-data 目录名)
handlerName firebase_fdw_handler FDW 的 handler 函数名
validatorName firebase_fdw_validator FDW 的 validator 函数名
extensionName FirebaseFdw 对应 Wrappers 框架的扩展名
label Firebase 界面显示名
description Backend-as-a-Service with real-time database 界面描述
categories ['devtools', 'auth'] 集成分类(开发工具 / 认证)

Remote Server 的两个必填选项

在 SQL 层面,Remote Server 对应一个 CREATE SERVER。Firebase Wrapper 的 server 级选项只有两个,且都必填:

选项名 标签 是否加密存储 说明
project_id Project ID Firebase 项目的 ID,只允许字母、数字与连字符
sa_key_id Service Account Key encrypted: true,多行文本域) 服务账号密钥的完整 JSON,用于以 Admin 权限访问该 Firebase 项目

sa_key_id 标记为加密存储,意味着 Studio 只会在服务端加密保存该密钥,不会明文回显。服务账号 JSON 需要在 Firebase 控制台的 Project Settings → Service Accounts 中生成(Studio 的常量里把该入口标注为 urlHelper 指向 Firebase Admin SDK 的初始化文档)。

支持的对象一:Users(Firebase Auth 用户)

常量中第一个表模板 label 为 Users,描述为 "Shows your Firebase users",即把 Firebase Auth 的用户列表映射为外表。列结构固定为四列:

列名 类型 说明
uid text Firebase 用户 ID
email text 用户邮箱
created_at timestamp 创建时间
attrs jsonb 其余字段(自定义声明、手机号、头像等)

对应的表级 options 及其默认值:

选项 默认值 可否编辑 说明
object auth/users 否(editable: false 锁定的 Auth 用户端点
base_url https://identitytoolkit.googleapis.com/v1/projects 可编辑 Identity Toolkit API 前缀
limit 10000 可编辑 单次拉取行数上限

支持的对象二:Firestore Collection(任意集合)

第二个表模板 label 为 Firestore Collection,描述为 "Map to a Firestore collection",即把 Firestore 中任意集合映射为外表。列结构同样四列:

列名 类型 说明
name text 文档标识
created_at timestamp 创建时间
updated_at timestamp 更新时间
attrs jsonb 文档正文(嵌套字段拍平到 jsonb)

表级 options

选项 默认值 / 占位符 可否编辑 说明
object 占位符 firestore/[collection_id] 是(必填) firestore/ 前缀 + 集合 ID,决定映射哪个集合
base_url https://firestore.googleapis.com/v1beta1/projects 是(必填) Firestore Admin API 前缀
limit 10000 是(必填) 单次拉取行数上限

两类对象的共同点值得注意:文档正文都是 jsonb 兜底attrs 列)。这呼应了概览文档开头"Firebase 是非关系型平台"的判断——非结构化的文档字段被序列化进 attrs,需要时用 Postgres 的 JSON 操作符(->->>jsonb_path_exists 等)再行拆解。

SQL 实战:创建 server、外表并查询

Wrappers 框架在平台侧预装了扩展,实际使用时按标准 FDW 语法创建 server 与外表即可。以下 SQL 与上面常量中的字段名、默认值一一对应(扩展名取自常量中的 extensionName: 'FirebaseFdw',SQL 中按 Postgres 扩展命名惯例写作 firebase_fdw):

-- 1. 扩展(Studio 常量中 extensionName 为 FirebaseFdw)
create extension if not exists firebase_fdw;

-- 2. Remote Server:project_id + sa_key_id(加密存储的服务账号 JSON)
create server if not exists firebase_server
  foreign data wrapper firebase_fdw
  options (
    project_id 'my-firebase-project',
    sa_key_id '<service-account-key-json>'
  );

-- 3a. 外表:Firebase Auth 用户(object 固定为 auth/users)
create foreign table firebase.firebase_users (
  uid text,
  email text,
  created_at timestamp,
  attrs jsonb
)
server firebase_server
options (
  object 'auth/users',
  base_url 'https://identitytoolkit.googleapis.com/v1/projects',
  limit '10000'
);

-- 3b. 外表:某个 Firestore 集合(object 为 firestore/[collection_id])
create foreign table firebase.firestore_orders (
  name text,
  created_at timestamp,
  updated_at timestamp,
  attrs jsonb
)
server firebase_server
options (
  object 'firestore/orders',
  base_url 'https://firestore.googleapis.com/v1beta1/projects',
  limit '10000'
);

创建之后,QETL 式的实时查询就是普通 SQL,例如把 Firestore 里的订单与本地 auth.users 关联:

select
  auth.users.id as user_id,
  o.name as order_id,
  o.attrs ->> 'total' as total
from
  firebase.firestore_orders o
  join auth.users
    on auth.users.email = o.attrs ->> 'email'
where
  o.attrs ? 'vip';

也可以走批量 ETL,把拉取结果固化成本地表(配合 Wrappers 概览文档中介绍的 pg_cron 调度方式):

insert into public.firebase_users_snapshot (uid, email, created_at, attrs)
select uid, email, created_at, attrs
from firebase.firebase_users;

安全边界:FDW 没有行级安全

FDW 外表不提供 Row Level Security,这是 Wrappers 官方文档反复强调的安全红线(见 Foreign Data Wrappers 概览的 Security 一节)。落到 Firebase Wrapper 上,应遵循三条规则:

  1. 私有 schema:所有 Firebase 外表放在独立 schema(如示例中的 firebase)中,且该 schema 不要加入 API 配置里的 "Additional Schemas",避免被 PostgREST 直接暴露;
  2. 按需开窗:需要对外提供数据时,在 public schema 建 security definer 函数,在函数内对 attrs 等列做过滤后再返回;
  3. 收紧执行权限security definer 函数默认 anon 也能调用,必须 revoke 后只授权给目标角色。

以 Firebase 用户为例:

-- public 侧开窗函数:只暴露邮箱前缀匹配的脱敏字段
create function public.list_firebase_emails(prefix text)
returns table (email text)
language sql
security definer set search_path = ''
as $$
  select u.email
  from firebase.firebase_users u
  where u.email like prefix || '%'
$$;

-- 收回默认执行权,只授权给已登录用户
revoke execute on function public.list_firebase_emails(prefix text) from public, anon;
grant execute on function public.list_firebase_emails(prefix text) to authenticated;

客户端即可通过 supabase.rpc('list_firebase_emails', { prefix: 'acme.' }) 访问,而不直接接触外表。

易混淆概念辨析:数据 Wrapper ≠ 第三方登录 ≠ 数据迁移

Firebase 与 Supabase 的交叉点有三个,容易混淆,这里用仓库中的实现代码做个区分:

  1. Firebase Wrapper(本文主题):数据层集成,用 FDW 读取 Firebase 数据,属于 Integrations 页的 Wrappers 条目,分类为 devtoolsauth
  2. Firebase Auth 第三方登录:认证层集成,让 Firebase 签发的 ID Token 直接当作 Supabase 的 JWT 使用。对应实现是 CreateFirebaseAuthDialog.tsx:表单校验 firebaseProjectId 后,提交 oidcIssuerUrl: https://securetoken.google.com/${projectId},即注册 Firebase 项目作为 OIDC issuer——它不拉取任何数据,只是声明"接受哪个项目的令牌";
  3. Firestore 一次性迁移:若目标是彻底搬走 Firestore 数据而非持续同步,仓库中另有专门的迁移指南 Migrate from Firebase Firestore to Supabase:使用社区的 firebase-to-supabase 工具链,firestore2json.js <collectionName> [<batchSize>] [<limit>] 导出集合为 JSON(batchSize 默认 1000),json2supabase.js 再按 none/smallserial/serial/bigserial/uuid/firestore_id 主键策略导入 Postgres,并支持自定义 hook 把嵌套文档拆分成多张表。

小结

Firebase Wrapper 概览文档虽然只有三行,但它钉死了这个集成的本质:FDW。围绕这个本质,从 Wrappers.constants.ts 的常量可以还原出完整的操作面——server 级 project_id + 加密的 sa_key_id 两个必填项,两类可连接对象(auth/users 用户表与 firestore/[collection_id] 集合表),以及 base_urllimit(默认 10000)等表级选项。配合 FDW 无 RLS 的安全约束(私有 schema + security definer 开窗函数),Firebase Wrapper 就是一条"用 SQL 把 Firebase 当成 Postgres 的邻居"的完整链路:实时 join 走 QETL,周期性固化走批量 ETL,彻底搬迁则转向迁移工具链。

登录后查看全文
热门项目推荐
相关项目推荐