RLS 权限模式示例
本文汇总 CloudBase PostgreSQL 数据库中四种常见 RLS 权限模式以及两个进阶场景的完整 SQL 模板,可直接复制到你的项目中使用。每个模式都包含:
- 适用场景
- 完整建表 + GRANT + Policy 的 SQL
- 权限效果矩阵
💡 本文与云存储传统权限模式中的
READONLY/PRIVATE/ADMINWRITE/ADMINONLY同名,语义刻意对齐:一份心智模型,数据库和云存储通用。
1. READONLY — 所有人可读,仅创建者可写
适用场景:博客文章、产品目录、公共帖子、社区问答
SQL 模板
-- 建表(owner_id 自动绑定 JWT sub)
CREATE TABLE public.posts (
id serial PRIMARY KEY,
title text NOT NULL,
content text,
owner_id varchar(64) NOT NULL
DEFAULT (current_setting('request.jwt.claims', true)::json->>'sub'),
created_at timestamptz DEFAULT now()
);
ALTER TABLE public.posts ENABLE ROW LEVEL SECURITY;
-- 表级权限
GRANT SELECT ON public.posts TO anon;
GRANT SELECT, INSERT, UPDATE, DELETE ON public.posts TO authenticated;
GRANT USAGE, SELECT ON SEQUENCE public.posts_id_seq TO authenticated;
GRANT ALL ON public.posts TO service_role;
GRANT USAGE, SELECT ON SEQUENCE public.posts_id_seq TO service_role;
-- RLS 策略
-- 所有人可读
CREATE POLICY posts_select ON public.posts
FOR SELECT
USING (true);
-- 登录用户可创建(但 owner_id 必须是自己)
CREATE POLICY posts_insert ON public.posts
FOR INSERT TO authenticated
WITH CHECK (owner_id = (current_setting('request.jwt.claims', true)::json->>'sub'));
-- 仅创建者可更新
CREATE POLICY posts_update ON public.posts
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'));
-- 仅创建者可删除
CREATE POLICY posts_delete ON public.posts
FOR DELETE TO authenticated
USING (owner_id = (current_setting('request.jwt.claims', true)::json->>'sub'));
权限效果
| 操作 | anon | authenticated(创建者) | authenticated(非创建者) | service_role |
|---|---|---|---|---|
| SELECT | ✅ | ✅ | ✅ | ✅ |
| INSERT | ❌ | ✅ | ✅(只能创建自己的) | ✅ |
| UPDATE | ❌ | ✅(仅自己的) | ❌ | ✅ |
| DELETE | ❌ | ✅(仅自己的) | ❌ | ✅ |
2. PRIVATE — 仅创建者可读写
适用场景:私人笔记、个人设置、私密消息、待办清单
与 READONLY 的关键区别
- SELECT 策略也加上
owner_id判断(用户间完全隔离) - 不授予
anon任何权限
SQL 模板
CREATE TABLE public.private_notes (
id serial PRIMARY KEY,
content text NOT NULL,
owner_id varchar(64) NOT NULL
DEFAULT (current_setting('request.jwt.claims', true)::json->>'sub'),
created_at timestamptz DEFAULT now()
);
ALTER TABLE public.private_notes ENABLE ROW LEVEL SECURITY;
-- 不授予 anon 任何权限
GRANT SELECT, INSERT, UPDATE, DELETE ON public.private_notes TO authenticated;
GRANT USAGE, SELECT ON SEQUENCE public.private_notes_id_seq TO authenticated;
GRANT ALL ON public.private_notes TO service_role;
GRANT USAGE, SELECT ON SEQUENCE public.private_notes_id_seq TO service_role;
-- SELECT 策略:仅创建者可见
CREATE POLICY notes_select ON public.private_notes
FOR SELECT TO authenticated
USING (owner_id = (current_setting('request.jwt.claims', true)::json->>'sub'));
-- INSERT 策略:owner_id 必须是自己
CREATE POLICY notes_insert ON public.private_notes
FOR INSERT TO authenticated
WITH CHECK (owner_id = (current_setting('request.jwt.claims', true)::json->>'sub'));
-- UPDATE 策略:仅创建者可更新且不能改 owner_id
CREATE POLICY notes_update ON public.private_notes
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 notes_delete ON public.private_notes
FOR DELETE TO authenticated
USING (owner_id = (current_setting('request.jwt.claims', true)::json->>'sub'));
权限效果
每个用户只能看到自己的数据,用户之间完全隔离。
3. ADMINWRITE — 所有人可读,仅管理员可写
适用 场景:公告板、系统配置、字典表、全局常量
关键思路
不授予 anon / authenticated 任何写权限——从表级权限层面就阻止写入;只有 service_role(BYPASSRLS)可以写。
SQL 模板
CREATE TABLE public.announcements (
id serial PRIMARY KEY,
title text NOT NULL,
content text,
published boolean DEFAULT true,
created_at timestamptz DEFAULT now()
);
ALTER TABLE public.announcements ENABLE ROW LEVEL SECURITY;
-- 仅授予读权限
GRANT SELECT ON public.announcements TO anon;
GRANT SELECT ON public.announcements TO authenticated;
-- 不授予 INSERT/UPDATE/DELETE 给 anon/authenticated
GRANT ALL ON public.announcements TO service_role;
GRANT USAGE, SELECT ON SEQUENCE public.announcements_id_seq TO service_role;
-- SELECT 策略:仅显示 published=true 的公告
CREATE POLICY announcements_select ON public.announcements
FOR SELECT
USING (published = true);
权限效果
| 操作 | anon | authenticated | service_role |
|---|---|---|---|
| SELECT(已发布) | ✅ | ✅ | ✅ |
| SELECT(未发布) | ❌ | ❌ | ✅ |
| INSERT / UPDATE / DELETE | ❌ | ❌ | ✅ |
4. ADMINONLY — 仅管理员可读写
适用场景:系统日志、审计记录、后台配置、敏感数据表
关键思路
不授予 anon / authenticated 任何权限 + 不创建任何 Policy——最严格的双重锁定:没有 GRANT 过不了第一层,没有 Policy 过不了第二层(但 service_role 具备 BYPASSRLS,自动穿透)。
SQL 模板
CREATE TABLE public.system_config (
key text PRIMARY KEY,
value jsonb NOT NULL,
updated_at timestamptz DEFAULT now()
);
ALTER TABLE public.system_config ENABLE ROW LEVEL SECURITY;
-- 仅授予 service_role
GRANT ALL ON public.system_config TO service_role;
-- 不授予 anon / authenticated 任何权限
-- 不创建任何 RLS Policy
-- 结果:只有 service_role 能访问
权限效果
除了 service_role,其他所有角色完全无法访问。