已配置Cognito用户池,如何关联Postgres实现行级访问控制?
配置Cognito用户池与Postgres行级访问控制(RLS)的步骤
1. Postgres侧RLS基础准备
- 给需要做行级控制的业务表添加用户标识列,比如
cognito_user_id(类型设为varchar),用来存储Cognito用户的唯一ID(对应Cognito返回的sub字段) - 开启目标表的RLS:
ALTER TABLE your_business_table ENABLE ROW LEVEL SECURITY;
- 创建通用Postgres角色,供所有Cognito认证用户使用:
CREATE ROLE cognito_authenticated_user NOLOGIN; -- 按需授予操作权限,比如仅查询或增删改查 GRANT SELECT, INSERT, UPDATE, DELETE ON your_business_table TO cognito_authenticated_user;
2. Cognito身份与Postgres的映射逻辑
不需要为每个Cognito用户单独创建Postgres角色,通过应用层传递身份信息+Postgres会话变量实现关联:
- 应用层验证Cognito JWT有效性后,提取用户的
sub字段(唯一ID) - 用一个拥有
SET ROLE权限的服务账号连接Postgres,执行以下语句切换角色并设置会话变量:
SET ROLE cognito_authenticated_user; SET app.current_cognito_user_id = '用户的sub值';
- 提前在Postgres中创建会话变量的Schema和权限:
CREATE SCHEMA IF NOT EXISTS app; CREATE OR REPLACE FUNCTION app.set_current_user_id(user_id varchar) RETURNS void AS $$ BEGIN SET app.current_cognito_user_id = user_id; END; $$ LANGUAGE plpgsql; GRANT USAGE ON SCHEMA app TO cognito_authenticated_user;
3. 编写RLS策略
针对业务表编写策略,限制用户仅能访问自己的数据:
-- 通用全操作策略 CREATE POLICY user_data_access_policy ON your_business_table FOR ALL TO cognito_authenticated_user USING (cognito_user_id = current_setting('app.current_cognito_user_id')::varchar) WITH CHECK (cognito_user_id = current_setting('app.current_cognito_user_id')::varchar);
如果需要拆分读写权限,可以单独创建策略:
-- 只读策略 CREATE POLICY user_read_policy ON your_business_table FOR SELECT TO cognito_authenticated_user USING (cognito_user_id = current_setting('app.current_cognito_user_id')::varchar); -- 写入策略(确保用户只能插入/更新自己的行) CREATE POLICY user_write_policy ON your_business_table FOR INSERT, UPDATE TO cognito_authenticated_user WITH CHECK (cognito_user_id = current_setting('app.current_cognito_user_id')::varchar);
4. 应用层核心注意事项
- 严格验证Cognito JWT的签名、过期时间、受众(Audience)等字段,避免无效身份进入数据库
- 服务账号仅保留最小权限:只能执行
SET ROLE到cognito_authenticated_user,禁止直接操作业务表 - 每次数据库会话必须重新设置
app.current_cognito_user_id,避免会话复用导致的权限泄漏
5. 验证环节
- 用不同Cognito用户的身份访问应用,检查是否只能查询/修改自己的行数据
- 尝试直接登录
cognito_authenticated_user角色(会失败,因为设置了NOLOGIN) - 测试未设置
app.current_cognito_user_id的场景,确认RLS会拦截所有数据访问
内容的提问来源于stack exchange,提问作者Kival M
相关产品推荐
相关产品推荐

