Postgres 政策的范围是什么?

What is the scope of Postgres policies?

我正在努力研究 Postgres 中的行级安全性。不幸的是,文档在这个问题上不是很详细。我的问题如下:

我有两个 table:locationslocations_owners。在 INSERT 上为位置设置了 TRIGGER,它会自动向 locations_owners table 添加一个新行,包括 request.jwt.claim.sub variable

一切正常,但是当我想像这样为 DELETE 创建策略时:

CREATE POLICY location_delete ON eventzimmer.locations FOR DELETE TO organizer USING(
    (SELECT EXISTS (SELECT name FROM protected.locations_owners AS owners WHERE owners.name = name AND owners.sub = (SELECT current_setting('request.jwt.claim.sub', true))))
);

无论实际内容如何,​​它的计算结果始终为真。我知道我可以在这里使用 SELECT 调用自定义过程,但是我最终遇到了以下问题:

我对 PostgreSQL 的(否则)非常好的文档中惊人地缺少大量信息感到有点困惑。这些信息在哪里?我怎样才能找到它?

为了完整起见,我还附上了下面的列定义:

CREATE TABLE eventzimmer.locations (
  name varchar PRIMARY KEY NOT NULL,
  latitude float NOT NULL,
  longitude float NOT NULL
);

CREATE TABLE IF NOT EXISTS protected.locations_owners (
    name varchar NOT NULL REFERENCES eventzimmer.locations(name) ON DELETE CASCADE,
    sub varchar NOT NULL
);

一旦您了解了行级安全性的实现方式,许多问题就会变得清晰:策略中的条件将自动添加到查询中,就像您添加另一个 WHERE 条件一样。

使用EXPLAIN查看查询计划,您将在其中看到策略的条件。

  • 因此您可以使用 table 中定义策略的任何列。

    基本上,您可以在策略定义中使用您可以在 WHERE 条件下使用的任何内容:函数调用、子查询等。

    如果需要消除歧义,您还可以使用 table 名称限定列名称。这可以在您的示例中的策略中使用:不合格的 name 被解释为 owners.name,因此测试总是成功的。要修复此政策,请使用 locations.name 而不是 name

  • 没有神奇的 user_name 变量,我不知道你从哪里得到的。但是,有 current_user 功能,它始终可用,当然也可以在策略定义中使用。

  • WITH CHECKINSERTUPDATE 添加的新行必须满足的条件。由于 DELETE 不添加任何数据,因此 WITH CHECK 不适用于它。