快速体验
阅读前建议先了解 PG 模式概述,明确 PostgreSQL、身份认证、云存储和权限模型的关系。
本文以一个最小待办应用为例,演示 CloudBase PostgreSQL 数据库下从建表 → 启用 RLS → 授权 → 写策略 → SDK 调用的完整流程,帮你在 5~10 分钟内跑通一个安全的多用户数据访问链路。
前置准备
- 已 创建 PG 模式的云开发环境,并记录:
- 环境 ID(例如
pg-test-3gxmdbdb580ecfd1) - Publishable Key(前端使用,对应
anon角色) - API Key(后端使用,对应
service_role,严禁暴露前端)
- 环境 ID(例如
- 三种角色与 Key 详见 PG:身份认证,双层权限模型详见 架构与权限模型
Key 的获取
Publishable Key / API Key 可在控制台创建(或通过 YUNAPI 的 CreateApiKey 创建)。
第一步:建表
创建一张 todos 表。可以使用 SQL 编辑器(控制台 → 数据库 → SQL 编辑器)直接执行:
CREATE TABLE public.todos (
id bigserial PRIMARY KEY,
title varchar(255) NOT NULL,
is_completed boolean NOT NULL DEFAULT false,
-- ⭐ owner_id 自动从 JWT 读取当前用户 ID
owner_id varchar(64) NOT NULL
DEFAULT (current_setting('request.jwt.claims', true)::json->>'sub'),
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX idx_todos_owner_id ON public.todos(owner_id);
关键:
owner_id的默认值绑定 JWTsub,前端无需传入owner_id,从源头杜绝身份伪造。
第二步:启用 RLS
ALTER TABLE public.todos ENABLE ROW LEVEL SECURITY;
启用 RLS 后,若未配置任何 Policy,所有非 service_role 用户都无法访问任何数据(默认拒绝)。继续下一步。
第三步:授予表级权限(GRANT)
表级 GRANT 控制每种角色能对表执行哪些类型的操作:
-- 匿名用户:不给任何权限(未登录不能操作个人待办)
-- 登录用户:可读可写自己的待办
GRANT SELECT, INSERT, UPDATE, DELETE ON public.todos TO authenticated;
GRANT USAGE, SELECT ON SEQUENCE public.todos_id_seq TO authenticated;
-- 管理员:全部权限
GRANT ALL ON public.todos TO service_role;
GRANT USAGE, SELECT ON SEQUENCE public.todos_id_seq TO service_role;
第四步:创建 RLS 策略(Policy)
行级 Policy 控制每种角色能操作哪些具体的行:
-- SELECT:登录用户仅能读自己的待办
CREATE POLICY todos_select_own ON public.todos
FOR SELECT TO authenticated
USING (owner_id = (current_setting('request.jwt.claims', true)::json->>'sub'));
-- INSERT:登录用户仅能写入 owner_id = 自己 的记录
CREATE POLICY todos_insert_own ON public.todos
FOR INSERT TO authenticated
WITH CHECK (owner_id = (current_setting('request.jwt.claims', true)::json->>'sub'));
-- UPDATE:登录用户仅能更新自己的记录,且不能把 owner_id 改成别人
CREATE POLICY todos_update_own ON public.todos
FOR UPDATE TO authenticated
USING (owner_id = (current_setting('request.jwt.claims', true)::json->>'sub'))
WITH CHECK (owner_id = (current_setting('request.jwt.claims', true)::json->>'sub'));
-- DELETE:登录用户仅能删自己的记录
CREATE POLICY todos_delete_own ON public.todos
FOR DELETE TO authenticated
USING (owner_id = (current_setting('request.jwt.claims', true)::json->>'sub'));
通过云 API 自动化部署
上述 SQL 可通过云 API ExecutePGSql 执行(适合 CI/CD)。注意 部分 DDL 在 API 路径下需要用 DO $$ BEGIN EXECUTE '...'; END $$ 包装后重试,详见 架构与权限模型 - ExecutePGSql。
第五步:通过 SDK 读写数据
安装
npm install @cloudbase/js-sdk
使用
import cloudbase from '@cloudbase/js-sdk';
// 也可以传入 accessKey: '<Publishable Key>',这样未显式登录时即以 anon 身份访问
const app = cloudbase.init({ env: '<云开发环境 ID>' });
const auth = app.auth;
// 1. 登录(匿名 / 账号密码 / 第三方均可,此处以匿名为例)
// 匿名登录后 JWT 中 role=anon 但带真实 sub,可作为 owner_id 归属字段使用
await auth.signInAnonymously();
// 2. 访问 PG 数据库
const db = app.rdb();
// 查询:RLS 自动过滤,只返回当前用户的待办
const { data, error } = await db
.from('todos')
.select('*')
.eq('is_completed', false);
// 新增:owner_id 由数据库默认值自动填充为 JWT 的 sub
await db.from('todos').insert({ title: '写一篇文档' });
// 更新:RLS 只允许改自己的
await db.from('todos').update({ is_completed: true }).eq('id', 1);
// 删除:RLS 只允许删自己的
await db.from('todos').delete().eq('id', 1);
SDK 用法说明
app.auth是属性,不是方法(不要写app.auth())- 账号密码登录使用
auth.signInWithPassword({ username, password }) - 详细 API 见 JS SDK - PostgreSQL 数据库 与 JS SDK - 认证
第六步:直接使用 REST API(可选)
若无 SDK 场景,可直接调 PostgREST RESTful API:
# 登录
curl -X POST "https://<envId>.api.tcloudbasegateway.com/auth/v1/signin/anonymously" \
-H "Content-Type: application/json" \
-d '{}'
# 响应:{ "access_token": "eyJhbG...", ... }
# 查询
curl "https://<envId>.api.tcloudbasegateway.com/v1/rdb/rest/todos?select=*&is_completed=eq.false" \
-H "Authorization: Bearer <access_token>"
# 新增(owner_id 省略,由 DEFAULT 自动填充)
curl -X POST "https://<envId>.api.tcloudbasegateway.com/v1/rdb/rest/todos" \
-H "Authorization: Bearer <access_token>" \
-H "Prefer: return=representation" \
-H "Content-Type: application/json" \
-d '{"title":"写一篇文档"}'
验证 RLS 是否生效
- 未登录访问(不带 Authorization 或用
anon身份调用)→ 无权限,返回空数组或 403 - 登录后访问 → 仅返回自己的数据
- 伪造 owner_id(前端恶意传入
"owner_id": "other-user")→ 被WITH CHECK拒绝 - 尝试读其他用户的待办(例如
?owner_id=eq.other-user)→ 即使带过滤条件,USING策略仍然只返回自己的数据
常见陷阱
- 启用了 RLS 但没写 Policy → 所有非
service_role请求都被拒绝 - 写了 Policy 但忘记 GRANT → 表级权限不通过
- UPDATE 只写了
USING,没写WITH CHECK→ 用户可以把owner_id改成别人,窃取数据 - 在前端代码中使用
API Key→ 等于所有数据完全暴露(service_roleBYPASSRLS) - 使用
serial/bigserial主键忘记授予SEQUENCE权限 → INSERT 报权限错误 - DDL 通过
ExecutePGSql时部分语句直接报错 → 失败时用DO $$ BEGIN EXECUTE '...'; END $$包装重试
下一步
- 框架快速入门:
- 深入阅读:
- PG:身份认证(含三角色 + JWT)
- PG 模式云存储
- 架构与权限模型
- 基础权限管理
- PostgREST RESTful API