On this page
表 240.按命令类型应用的策略
CREATE POLICY
创建策略—为表定义新的行级安全策略
Synopsis
CREATE POLICY name ON table_name
[ AS { PERMISSIVE | RESTRICTIVE } ]
[ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ]
[ TO { role_name | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ]
[ USING ( using_expression ) ]
[ WITH CHECK ( check_expression ) ]
Description
CREATE POLICY
命令为表定义新的行级安全策略。请注意,必须在表上启用行级安全性(使用ALTER TABLE ... ENABLE ROW LEVEL SECURITY
),才能应用创建的策略。
策略授予选择,插入,更新或删除与相关策略表达式匹配的行的权限。将对照USING
中指定的表达式检查现有的表行,而对照WITH CHECK
中指定的表达式检查将通过INSERT
或UPDATE
创建的新行。当USING
表达式对于给定的行返回 true 时,则该行对用户可见,而如果返回 false 或 null,则该行不可见。当WITH CHECK
表达式的一行返回 true 时,该行将被插入或更新,而如果返回 false 或 null 则将发生错误。
对于INSERT
和UPDATE
语句,在触发BEFORE
触发器之后以及进行任何实际数据修改之前,将强制执行WITH CHECK
表达式。因此,BEFORE ROW
触发器可能会修改要插入的数据,从而影响安全策略检查的结果。 WITH CHECK
表达式在任何其他约束之前被强制执行。
策略名称是按表的。因此,一个策略名称可用于许多不同的表,并为每个表定义一个适合该表的定义。
策略可以应用于特定命令或特定角色。除非另有说明,否则新创建的策略的默认设置是它们适用于所有命令和角色。多个策略可能适用于单个命令。请参阅下面的更多细节。 Table 240总结了不同类型的策略如何应用于特定命令。
对于同时具有USING
和WITH CHECK
表达式(ALL
和UPDATE
)的策略,如果未定义WITH CHECK
表达式,则将使用USING
表达式来确定哪些行可见(正常USING
情况)以及允许哪些新行被添加(WITH CHECK
大小写)。
如果为表启用了行级安全性,但是不存在适用的策略,那么将采用“默认拒绝”策略,这样就不会显示或更新任何行。
Parameters
name
- 要创建的策略的名称。该名称必须与表的任何其他策略的名称不同。
table_name
- 该策略适用于的表的名称(可选,由模式限定)。
PERMISSIVE
- 指定该策略将被创建为许可策略。适用于给定查询的所有宽松策略都将使用布尔值“ OR”运算符组合在一起。通过创建许可策略,Management 员可以将记录添加到可以访问的记录集中。默认情况下,策略是允许的。
RESTRICTIVE
- 指定该策略将被创建为限制性策略。适用于给定查询的所有限制性策略将使用布尔值“ AND”运算符组合在一起。通过创建限制性策略,Management 员可以减少可访问的记录集,因为必须为每个记录传递所有限制性策略。
请注意,在限制性策略可以有效地用于减少记录访问之前,至少需要一个许可策略来授予对记录的访问权限。如果仅存在限制性策略,则将无法访问任何记录。当存在宽松策略和限制性策略的混合时,除了所有限制性策略之外,仅当至少一项宽松策略通过时,才可以访问记录。
command
- 策略适用的命令。有效选项为
ALL
,SELECT
,INSERT
,UPDATE
和DELETE
。ALL
是默认值。有关如何应用这些内容的详细信息,请参见下文。
- 策略适用的命令。有效选项为
role_name
- 将策略应用到的角色。默认值为
PUBLIC
,它将对所有角色应用该策略。
- 将策略应用到的角色。默认值为
using_expression
- 任何 SQL 条件表达式(返回
boolean
)。条件表达式不能包含任何聚合或窗口函数。如果启用了行级安全性,则此表达式将添加到引用该表的查询中。表达式返回 true 的行将可见。表达式返回 false 或 null 的任何行将对用户不可见(在SELECT
中),并且不可用于修改(在UPDATE
或DELETE
中)。这样的行被静默抑制;没有错误的报告。
- 任何 SQL 条件表达式(返回
check_expression
- 任何 SQL 条件表达式(返回
boolean
)。条件表达式不能包含任何聚合或窗口函数。如果启用了行级安全性,则此表达式将在对该表的INSERT
和UPDATE
查询中使用。仅允许表达式计算为 true 的行。如果对于任何插入的记录或更新产生的任何记录,表达式的计算结果为 false 或 null,则将引发错误。请注意,*check_expression
*是针对该行的建议新内容而不是原始内容进行评估的。
- 任何 SQL 条件表达式(返回
Per-Command Policies
ALL
- 对策略使用
ALL
意味着它将适用于所有命令,而不管命令的类型如何。如果存在ALL
策略并且存在更具体的策略,则将同时应用ALL
策略和一个或更具体的策略。另外,如果只定义了USING
表达式,则在两种情况下都使用USING
表达式将ALL
策略应用于查询的选择端和修改端。
- 对策略使用
例如,如果发出了UPDATE
,则ALL
策略将同时适用于UPDATE
能够选择哪些行作为要更新的行(应用USING
表达式)以及所产生的更新行,以检查它们是否适用允许将其添加到表中(如果定义了,则应用WITH CHECK
表达式,否则应用USING
表达式)。如果INSERT
或UPDATE
命令尝试向表中添加未通过ALL
策略的WITH CHECK
表达式的行,则整个命令将被中止。
SELECT
- 对策略使用
SELECT
意味着它将应用于SELECT
查询,并且在为该策略定义的关系上需要SELECT
权限时。结果是,在SELECT
查询期间仅返回通过SELECT
策略的关系中的那些记录,而需要SELECT
权限的查询(例如UPDATE
)也将仅看到SELECT
策略所允许的那些记录。SELECT
策略不能具有WITH CHECK
表达式,因为它仅适用于从关系中检索记录的情况。
- 对策略使用
INSERT
- 对策略使用
INSERT
意味着它将应用于INSERT
命令。插入的未通过此策略的行将导致违反策略错误,并且整个INSERT
命令将被中止。INSERT
策略不能具有USING
表达式,因为它仅适用于将记录添加到关系中的情况。
- 对策略使用
请注意,INSERT
和ON CONFLICT DO UPDATE
仅检查INSERT
路径附加到关系的行的INSERT
策略的WITH CHECK
表达式。
UPDATE
- 对策略使用
UPDATE
意味着它将应用于UPDATE
,SELECT FOR UPDATE
和SELECT FOR SHARE
命令以及INSERT
命令的辅助ON CONFLICT DO UPDATE
子句。由于UPDATE
涉及提取现有记录并将其替换为新的修改记录,因此UPDATE
策略接受USING
表达式和WITH CHECK
表达式。USING
表达式确定UPDATE
命令将针对哪些记录进行操作,而WITH CHECK
表达式定义允许将哪些修改后的行存储回该关系中。
- 对策略使用
更新值未通过WITH CHECK
表达式的任何行都将导致错误,并且整个命令将被中止。如果仅指定USING
子句,则该子句将同时用于USING
和WITH CHECK
情况。
通常,UPDATE
命令还需要从要更新的关系中的列中读取数据(例如,在WHERE
子句或RETURNING
子句中,或在SET
子句右侧的表达式中)。在这种情况下,还需要对更新的关系具有SELECT
权限,并且除了UPDATE
策略之外,还将应用适当的SELECT
或ALL
策略。因此,除了被授予通过UPDATE
或ALL
策略更新行的权限之外,用户还必须有权访问通过SELECT
或ALL
策略更新的行。
当INSERT
命令具有辅助ON CONFLICT DO UPDATE
子句时,如果采用UPDATE
路径,则首先针对任何UPDATE
策略的USING
表达式检查要更新的行,然后针对WITH CHECK
表达式检查新的更新的行。但是请注意,与独立的UPDATE
命令不同,如果现有行未传递USING
表达式,则将引发错误(*绝不会避免UPDATE
路径)。
DELETE
- 对策略使用
DELETE
意味着它将应用于DELETE
命令。DELETE
命令将仅显示通过此策略的行。如果没有通过DELETE
策略的USING
表达式,则可能存在通过SELECT
可见的行,这些行不可删除。
- 对策略使用
在大多数情况下,DELETE
命令还需要从要删除的关系中的列中读取数据(例如,在WHERE
子句或RETURNING
子句中)。在这种情况下,该关系上还需要SELECT
权限,并且除了DELETE
策略之外,还将应用适当的SELECT
或ALL
策略。因此,除了被授予通过DELETE
或ALL
策略删除行的权限之外,用户还必须有权访问通过SELECT
或ALL
策略删除的行。
DELETE
策略不能具有WITH CHECK
表达式,因为它仅适用于从关系中删除记录的情况,因此没有要检查的新行。
Command | SELECT/ALL policy |
INSERT/ALL policy |
UPDATE/ALL policy |
DELETE/ALL policy |
|
---|---|---|---|---|---|
USING expression |
WITH CHECK expression |
USING expression |
WITH CHECK expression |
USING expression |
|
SELECT |
Existing row | — | — | — | — |
SELECT FOR UPDATE/SHARE |
Existing row | — | Existing row | — | — |
INSERT |
— | New row | — | — | — |
INSERT ... RETURNING |
新行[a] | New row | — | — | — |
UPDATE |
现有行和新行[a] | — | Existing row | New row | — |
DELETE |
现有的[a]行 | — | — | — | Existing row |
ON CONFLICT DO UPDATE |
现有和新行 | — | Existing row | New row | — |
[a]如果需要对现有或新行进行读取访问(例如,引用该关系中的列的WHERE 或RETURNING 子句)。 |
|||||
多种 Policy 的应用
当不同命令类型的多个策略应用于同一命令(例如,SELECT
和UPDATE
策略应用于UPDATE
命令)时,用户必须同时具有两种类型的权限(例如,从关系中选择行的权限以及进行更新的权限)。因此,使用AND
运算符将一种策略类型的表达式与另一种策略类型的表达式组合在一起。
当同一命令类型的多个策略应用于同一命令时,则必须至少有一个PERMISSIVE
策略授予对该关系的访问权限,并且所有RESTRICTIVE
策略都必须通过。因此,使用OR
组合所有PERMISSIVE
策略表达式,使用AND
组合所有RESTRICTIVE
策略表达式,使用AND
组合结果。如果没有PERMISSIVE
策略,则拒绝访问。
请注意,出于组合多个策略的目的,ALL
策略被视为与所应用的其他任何类型的策略具有相同的类型。
例如,在同时要求SELECT
和UPDATE
权限的UPDATE
命令中,如果每种类型都有多个适用的策略,则将它们组合如下:
expression from RESTRICTIVE SELECT/ALL policy 1
AND
expression from RESTRICTIVE SELECT/ALL policy 2
AND
...
AND
(
expression from PERMISSIVE SELECT/ALL policy 1
OR
expression from PERMISSIVE SELECT/ALL policy 2
OR
...
)
AND
expression from RESTRICTIVE UPDATE/ALL policy 1
AND
expression from RESTRICTIVE UPDATE/ALL policy 2
AND
...
AND
(
expression from PERMISSIVE UPDATE/ALL policy 1
OR
expression from PERMISSIVE UPDATE/ALL policy 2
OR
...
)
Notes
您必须是表的所有者才能为其创建或更改策略。
尽管策略将用于对数据库中的表进行显式查询,但是当系统执行内部参照完整性检查或验证约束时,策略将不会应用。这意味着可以通过间接方式确定给定值的存在。例如,尝试将重复值插入到为主键或具有唯一约束的列中。如果插入失败,则用户可以推断该值已经存在。 (此示例假定策略允许用户插入他们不允许查看的记录.)另一个示例是允许用户将其插入引用另一个表(否则为隐藏表)的表中。用户可以通过将值插入到引用表中来确定其存在,如果成功,则表明该值存在于引用表中。可以通过精心设计策略来防止用户完全无法插入,删除或更新记录(这些记录可能表明他们原本无法查看的值)或使用生成的值(例如,替代键)来解决这些问题。而不是具有外部含义的键。
通常,系统将在出现在用户查询中的资格之前强制执行使用安全策略强加的筛选条件,以防止将受保护的数据无意中暴露给可能不值得信赖的用户定义功能。但是,系统(或系统 Management 员)标记为LEAKPROOF
的功能和运算符可能会在策略表达式之前进行评估,因为它们被认为是可信任的。
由于策略表达式是直接添加到用户查询中的,因此它们将以运行整个查询的用户权限运行。因此,使用给定策略的用户必须能够访问该表达式中引用的任何表或函数,否则在尝试查询已启用行级安全性的表时,他们将仅收到权限拒绝错误。但是,这不会改变视图的工作方式。与普通查询和视图一样,视图引用的表的权限检查和策略将使用视图所有者的权限以及适用于该视图所有者的任何策略。
其他讨论和实际示例可以在Section 5.7中找到。
Compatibility
CREATE POLICY
是 PostgreSQL 扩展。