CREATE ROW LEVEL SECURITY POLICY
功能描述
对表创建行访问控制策略。
注意事项
- 支持对行存表、行存分区表、复制表、unlogged表以及hash表定义行访问控制策略。
- 不支持外表或临时表定义行访问控制策略。
- 不支持对视图定义行访问控制策略。
- 同一张表上可以创建多个行访问控制策略,一张表最多创建100个行访问控制策略。
- 系统管理员不受行访问控制影响,可以查看表的全量数据。
- 通过SQL语句、视图、函数以及存储过程查询包含行访问控制策略的表,都会受影响。
- 不支持对添加了行级访问控制策略的表字段进行修改数据类型操作。
- 当对表创建了行访问控制策略,只有打开该表的行访问控制开关(ALTER TABLE ... ENABLE ROW LEVEL SECURITY),策略才能生效,否则不生效。
- 当前行访问控制影响数据表的读取操作(SELECT、UPDATE或DELETE),暂不影响数据表的写入操作(INSERT以及MERGE INTO)。
- 表所有者或系统管理员可以在USING子句中创建表达式,在客户端执行数据表读取操作时,数据库后台在查询重写阶段会将满足条件的表达式拼接并应用到执行计划中。针对数据表的每一条元组,当USING表达式返回true时,元组对当前用户可见,当USING表达式返回false或null时,元组对当前用户不可见。
- 行访问控制策略名称仅针对于指定表,同一个数据表上不能有同名的行访问控制策略;对不同的数据表,可以存在同名的行访问控制策略。
语法格式
1 2 3 4 5 |
CREATE [ ROW LEVEL SECURITY ] POLICY policy_name ON table_name [ AS { PERMISSIVE | RESTRICTIVE } ] [ FOR { ALL | SELECT | UPDATE | DELETE } ] [ TO { role_name | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ] USING ( using_expression ); |

参数说明
- policy_name
行访问控制策略名称,同一个数据表上行访问控制策略名称不能相同。
- table_name
行访问控制策略的表名。
- PERMISSIVE | RESTRICTIVE
PERMISSIVE:指定行访问控制策略为宽容性策略,宽容性策略的条件用OR表达式拼接。
RESTRICTIVE:指定行访问控制策略为限制性策略,限制性策略的条件用AND表达式拼接。
拼接方式如下:
(using_expression_permissive_1 OR using_expression_permissive_2 ...) AND (using_expression_restrictive_1 AND using_expression_restrictive_2 ...)
未指定时默认为PERMISSIVE。
- command
当前行访问控制影响的SQL操作,可指定操作包括:ALL、SELECT、UPDATE以及DELETE。当未指定时,默认为ALL。
- ALL:影响SELECT、UPDATE以及DELETE类的所有操作。
- SELECT:SELECT类操作受行访问控制的影响,只能查看到满足条件(using_expression返回值为true)的元组数据,受影响的操作包括SELECT、SELECT FOR UPDATE/SHARE、UPDATE ... RETURNING以及DELETE ... RETURNING。
- UPDATE:UPDATE类操作受行访问控制的影响,只能更新满足条件(using_expression返回值为true)的元组数据,受影响的操作包括UPDATE、UPDATE ... RETURNING以及SELECT ... FOR UPDATE/SHARE。
- DELETE:DELETE类操作受行访问控制的影响,只能删除满足条件(using_expression返回值为true)的元组数据,受影响的操作包括DELETE以及DELETE ... RETURNING。
行访问控制策略与适配的SQL语法关系如表1所示。表1 ROW LEVEL SECURITY策略与适配SQL语法关系 Command
SELECT/ALL policy
UPDATE/ALL policy
DELETE/ALL policy
SELECT
Existing row
No
No
SELECT FOR UPDATE/SHARE
Existing row
Existing row
No
UPDATE
No
Existing row
No
UPDATE RETURNING
Existing row
Existing row
No
DELETE
No
No
Existing row
DELETE RETURNING
Existing row
No
Existing row
- role_name | PUBLIC | CURRENT_USER | SESSION_USER
行访问控制影响的数据库用户/角色。行访问控制策略可以应用到指定的用户/角色,也可应用到全部用户(PUBLIC);若未指定受影响的用户,默认为PUBLIC。
- role_name:指定的数据库用户。
- CURRENT_USER:当前执行环境的用户名。
- SESSION_USER:会话用户名。
- PUBLIC:影响所有数据库用户,可以指定多个受影响的数据库用户。
系统管理员不受行访问控制特性影响。
- using_expression
行访问控制的表达式(返回boolean值)。
- 条件表达式中不能包含agg函数和窗口(window)函数。
- 在查询重写阶段,如果数据表的行访问控制开关打开,满足条件的表达式会添加到计划树中。
- 针对数据表的每条元组,会进行表达式计算,只有表达式返回值为true时,行数据对用户才可见(SELECT、UPDATE、DELETE);当表达式返回false时,该元组对当前用户不可见,用户无法通过SELECT语句查看此元组,无法通过UPDATE语句更新此元组,无法通过DELETE语句删除此元组。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
--创建用户alice。 gaussdb=# CREATE USER alice PASSWORD '*********'; --创建用户bob。 gaussdb=# CREATE USER bob PASSWORD '*********'; --创建数据表all_data。 gaussdb=# CREATE TABLE public.all_data(id int, role varchar(100), data varchar(100)); --向数据表插入数据。 gaussdb=# INSERT INTO all_data VALUES(1, 'alice', 'alice data'); gaussdb=# INSERT INTO all_data VALUES(2, 'bob', 'bob data'); gaussdb=# INSERT INTO all_data VALUES(3, 'peter', 'peter data'); --将表all_data的读取权限赋予alice和bob用户。 gaussdb=# GRANT SELECT ON all_data TO alice, bob; --打开行访问控制策略开关。 gaussdb=# ALTER TABLE all_data ENABLE ROW LEVEL SECURITY; --创建行访问控制策略,当前用户只能查看用户自身的数据。 gaussdb=# CREATE ROW LEVEL SECURITY POLICY all_data_rls ON all_data USING(role = CURRENT_USER); --查看表all_data相关信息。 gaussdb=# \d+ all_data Table "public.all_data" Column | Type | Modifiers | Storage | Stats target | Description --------+------------------------+-----------+----------+--------------+------------- id | integer | | plain | | role | character varying(100) | | extended | | data | character varying(100) | | extended | | Row Level Security Policies: POLICY "all_data_rls" FOR ALL TO public USING (((role)::name = "current_user"())) Has OIDs: no Distribute By: HASH(id) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off, enable_rowsecurity=true --当前用户执行SELECT操作。 gaussdb=# SELECT * FROM all_data; id | role | data ----+-------+------------ 1 | alice | alice data 2 | bob | bob data 3 | peter | peter data (3 rows) gaussdb=# EXPLAIN(COSTS OFF) SELECT * FROM all_data; id | operation ----+------------------------------ 1 | -> Streaming (type: GATHER) 2 | -> Seq Scan on all_data (2 rows) --切换至alice用户执行SELECT操作。 gaussdb=# SET ROLE alice PASSWORD '********'; gaussdb=> SELECT * FROM all_data; id | role | data ----+-------+------------ 1 | alice | alice data (1 row) gaussdb=> EXPLAIN(COSTS OFF) SELECT * FROM all_data; id | operation ----+------------------------------ 1 | -> Streaming (type: GATHER) 2 | -> Seq Scan on all_data (2 rows) Predicate Information (identified by plan id) ---------------------------------------------------------------- 2 --Seq Scan on all_data Filter: ((role)::name = "current_user"()) Notice: This query is influenced by row level security feature (3 rows) --插入数据,因未授权插入权限,则会报错。 gaussdb=> INSERT INTO all_data VALUES(4, 'test', 'test data'); ERROR: Permission denied for relation all_data. DETAIL: N/A. --将表all_data的插入权限赋予alice用户。 gaussdb=> RESET ROLE; gaussdb=# GRANT INSERT ON all_data TO alice; --切换至alice用户并插入数据。 gaussdb=# SET ROLE alice PASSWORD '********'; gaussdb=> INSERT INTO all_data VALUES(4, 'alice', 'test data'); INSERT 0 1 --查询表all_data。 gaussdb=> SELECT * FROM all_data; id | role | data ----+-------+------------ 1 | alice | alice data 4 | alice | test data (2 rows) --删除行访问控制策略。 gaussdb=> RESET ROLE; gaussdb=# DROP ROW LEVEL SECURITY POLICY all_data_rls ON all_data; --删除数据表all_data。 gaussdb=# DROP TABLE public.all_data; --删除用户alice, bob。 gaussdb=# DROP USER alice, bob; |