CREATE POLICY — 为表定义新的行级安全策略
CREATE POLICYname
ONtable_name
[ AS { PERMISSIVE | RESTRICTIVE } ] [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ] [ TO {role_name
| PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [, ...] ] [ USING (using_expression
) ] [ WITH CHECK (check_expression
) ]
CREATE POLICY
命令为表定义新的行级安全策略。请注意,必须在表上启用行级安全(使用 ALTER TABLE ... ENABLE ROW LEVEL SECURITY
),才能应用创建的策略。
策略授予选择、插入、更新或删除与相关策略表达式匹配的行。现有表行根据 USING
中指定的表达式进行检查,而通过 INSERT
或 UPDATE
创建的新行则根据 WITH CHECK
中指定的表达式进行检查。当 USING
表达式对于给定行返回 true 时,该行对用户可见,而如果返回 false 或 null,则该行不可见。当 WITH CHECK
表达式对于某行返回 true 时,该行将被插入或更新,而如果返回 false 或 null,则会发生错误。
对于 INSERT
、UPDATE
和 MERGE
语句,WITH CHECK
表达式在触发 BEFORE
触发器之后以及在进行任何实际数据修改之前执行。因此,BEFORE ROW
触发器可能会修改要插入的数据,从而影响安全策略检查的结果。 WITH CHECK
表达式在任何其他约束之前执行。
策略名称是针对每个表的。因此,一个策略名称可以用于许多不同的表,并且每个表都有一个适合该表的定义。
策略可以应用于特定的命令或特定的角色。新创建策略的默认设置是它们适用于所有命令和角色,除非另有指定。多个策略可能适用于单个命令;有关更多详细信息,请参见下文。 表 297 总结了不同类型的策略如何应用于特定命令。
对于既可以有 USING
又可以有 WITH CHECK
表达式的策略(ALL
和 UPDATE
),如果未定义 WITH CHECK
表达式,则 USING
表达式将同时用于确定哪些行可见(正常的 USING
案例)以及允许添加哪些新行(WITH CHECK
案例)。
如果为表启用了行级安全,但不存在任何适用的策略,则假定为 “默认拒绝” 策略,因此任何行都不可见或不可更新。
name
要创建的策略的名称。这必须与表中任何其他策略的名称不同。
table_name
策略应用到的表的名称(可选地带模式限定)。
PERMISSIVE
指定策略要作为许可策略创建。所有适用于给定查询的许可策略将使用布尔 “OR” 运算符组合在一起。通过创建许可策略,管理员可以添加可以访问的记录集。策略默认为许可策略。
RESTRICTIVE
指定策略要作为限制性策略创建。所有适用于给定查询的限制性策略将使用布尔 “AND” 运算符组合在一起。通过创建限制性策略,管理员可以减少可以访问的记录集,因为所有限制性策略都必须通过每个记录才能生效。
请注意,在可以有效地使用限制性策略来减少访问之前,需要至少一个许可策略来授予对记录的访问权限。如果仅存在限制性策略,则任何记录都不可访问。当存在许可策略和限制性策略的混合时,只有在至少一个许可策略通过以及所有限制性策略都通过的情况下,记录才可访问。
command
策略应用到的命令。有效选项为 ALL
、SELECT
、INSERT
、UPDATE
和 DELETE
。 ALL
为默认值。有关这些应用方式的详细信息,请参见下文。
role_name
策略要应用到的角色。默认值为 PUBLIC
,这会将策略应用于所有角色。
using_expression
任何SQL条件表达式(返回 boolean
)。条件表达式不能包含任何聚合或窗口函数。如果启用了行级安全,则此表达式将添加到引用该表的查询中。表达式返回 true 的行将可见。表达式返回 false 或 null 的任何行对用户不可见(在 SELECT
中),并且不可修改(在 UPDATE
或 DELETE
中)。此类行将被静默抑制;不会报告错误。
check_expression
任何SQL条件表达式(返回 boolean
)。条件表达式不能包含任何聚合或窗口函数。如果启用了行级安全,则此表达式将用于针对该表的 INSERT
和 UPDATE
查询。只有表达式计算结果为 true 的行才允许。如果表达式对插入的任何记录或更新产生的任何记录计算结果为 false 或 null,则会抛出错误。请注意,check_expression
是针对行的拟议新内容进行评估的,而不是原始内容。
ALL
#对于策略使用 ALL
意味着它将应用于所有命令,而不管命令类型如何。如果存在 ALL
策略并且存在更具体的策略,则 ALL
策略和更具体的策略(或策略)都将应用。此外,ALL
策略将应用于查询的选择端和修改端,如果仅定义了 USING
表达式,则在这两种情况下都使用 USING
表达式。
例如,如果发出 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
操作的 MERGE
命令。未通过此策略的插入行将导致策略违规错误,并且整个 INSERT
命令将被中止。 INSERT
策略不能具有 USING
表达式,因为它仅适用于将记录添加到关联的情况。
请注意,带有 ON CONFLICT DO UPDATE
的 INSERT
仅检查 INSERT
策略的 WITH CHECK
表达式,以获取通过 INSERT
路径添加到关联的行。
UPDATE
#对于策略使用 UPDATE
意味着它将应用于 UPDATE
、SELECT FOR UPDATE
和 SELECT FOR SHARE
命令,以及 INSERT
命令的辅助 ON CONFLICT DO UPDATE
子句。包含 UPDATE
操作的 MERGE
命令也会受到影响。由于 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
策略更新行(s)的权限外,还必须通过 SELECT
或 ALL
策略访问正在更新的行(s)。
当 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
策略删除行(s)的权限外,还必须通过 SELECT
或 ALL
策略访问正在删除的行(s)。
DELETE
策略不能具有 WITH CHECK
表达式,因为它仅适用于从关系中删除记录的情况,因此没有新行可供检查。
表 297. 命令类型应用的策略
命令 | SELECT/ALL 策略 |
INSERT/ALL 策略 |
UPDATE/ALL 策略 |
DELETE/ALL 策略 |
|
---|---|---|---|---|---|
USING 表达式 |
WITH CHECK 表达式 |
USING 表达式 |
WITH CHECK 表达式 |
USING 表达式 |
|
SELECT |
现有行 | — | — | — | — |
SELECT FOR UPDATE/SHARE |
现有行 | — | 现有行 | — | — |
INSERT / MERGE ... THEN INSERT |
— | 新行 | — | — | — |
INSERT ... RETURNING |
新行 [a] | 新行 | — | — | — |
UPDATE / MERGE ... THEN UPDATE |
现有行和新行 [a] | — | 现有行 | 新行 | — |
DELETE |
现有行 [a] | — | — | — | 现有行 |
ON CONFLICT DO UPDATE |
现有行和新行 | — | 现有行 | 新行 | — |
[a] 如果需要对现有行或新行进行读取访问(例如,引用关系中列的 |
当多个不同命令类型的策略应用于同一命令时(例如,SELECT
和 UPDATE
策略应用于 UPDATE
命令),则用户必须同时拥有这两种类型的权限(例如,选择关系中的行的权限以及更新它们的权限)。因此,一种策略的表达式与另一种策略的表达式使用 AND
运算符组合。
当同一命令类型的多个策略应用于同一命令时,则必须至少有一个 PERMISSIVE
策略授予对关系的访问权限,并且所有 RESTRICTIVE
策略都必须通过。因此,所有 PERMISSIVE
策略表达式使用 OR
组合,所有 RESTRICTIVE
策略表达式使用 AND
组合,结果使用 AND
组合。如果没有 PERMISSIVE
策略,则拒绝访问。
请注意,为了组合多个策略的目的,ALL
策略被视为与正在应用的任何其他类型的策略具有相同的类型。
例如,在需要 SELECT
和 UPDATE
权限的 UPDATE
命令中,如果每种类型有多个适用的策略,则它们将按如下方式组合
expression
from RESTRICTIVE SELECT/ALL policy 1 ANDexpression
from RESTRICTIVE SELECT/ALL policy 2 AND ... AND (expression
from PERMISSIVE SELECT/ALL policy 1 ORexpression
from PERMISSIVE SELECT/ALL policy 2 OR ... ) ANDexpression
from RESTRICTIVE UPDATE/ALL policy 1 ANDexpression
from RESTRICTIVE UPDATE/ALL policy 2 AND ... AND (expression
from PERMISSIVE UPDATE/ALL policy 1 ORexpression
from PERMISSIVE UPDATE/ALL policy 2 OR ... )
您必须是表的拥有者才能为其创建或更改策略。
虽然策略将应用于针对数据库中表的显式查询,但当系统执行内部引用完整性检查或验证约束时,它们不会应用。这意味着存在间接方法来确定给定值是否存在。一个示例是尝试将重复值插入到作为主键或具有唯一约束的列中。如果插入失败,则用户可以推断该值已存在。(此示例假设用户被策略允许插入他们不允许查看的记录。)另一个示例是用户被允许插入到引用另一个隐藏表的表中。用户可以通过将值插入到引用表中来确定是否存在,其中成功表示该值存在于被引用表中。可以通过仔细设计策略来解决这些问题,以防止用户能够插入、删除或更新可能指示他们无法查看的值的任何记录,或者使用生成的值(例如,代理键)代替具有外部含义的键。
通常,系统将在用户查询中出现的限定条件之前执行使用安全策略强加的过滤条件,以防止意外地将受保护的数据暴露给可能不可信的用户定义函数。但是,系统(或系统管理员)标记为 LEAKPROOF
的函数和运算符可能会在策略表达式之前进行评估,因为它们被认为是可信的。
由于策略表达式直接添加到用户的查询中,因此它们将以运行整个查询的用户权限运行。因此,使用给定策略的用户必须能够访问表达式中引用的任何表或函数,否则在尝试查询启用了行级安全性的表时,他们只会收到权限被拒绝错误。但是,这不会改变视图的工作方式。与正常的查询和视图一样,被视图引用的表的权限检查和策略将使用视图所有者的权限以及应用于视图所有者的任何策略,除非视图使用 security_invoker
选项定义(请参阅 CREATE VIEW
)。
对于 MERGE
不存在单独的策略。相反,在执行 MERGE
时,将应用为 SELECT
、INSERT
、UPDATE
和 DELETE
定义的策略,具体取决于执行的操作。
可以在 第 5.9 节 中找到其他讨论和实际示例。
CREATE POLICY
是 PostgreSQL 扩展。
如果您在文档中看到任何不正确的内容、与您对特定功能的体验不符的内容或需要进一步澄清的内容,请使用 此表单 报告文档问题。