来自 JS 世界的 SQL 新手,需要有关触发器的一些建议。
我的用户有一个id
列,我的 GraphQL API 总是调用INSERT INTO .... RETURNING *
然后在 GraphQL 层上进行转换以返回我想要的。
目标是允许像INSERT INTO .... RETURNING *
使用 RLS 一样进行查询。
这些政策是:
CREATE POLICY USER_SELECT_RESTRICTIONS
ON "user"
FOR SELECT
USING ("id" = current_user_id() OR current_user_role() = 'admin' OR current_user_role() = 'partner');
CREATE POLICY USER_INSERT_RESTRICTIONS
ON "user"
FOR INSERT
WITH CHECK (true);
这对来宾用户(更多上下文在底部)来说是中断的,因为他们被允许INSERT
但不能SELECT
(因为只有授权用户才能选择他们自己的行的限制)。
所以我想在插入之前/之后以某种方式在触发器中手动设置用户设置(不知道是哪个,因为由于语法错误我无法前进)。
我已经尝试过了,但是在NEW.id
? (它只是对我说“语法错误”)
CREATE OR REPLACE FUNCTION after_user_insert()
RETURNS TRIGGER AS $$
BEGIN
SET LOCAL jwt.claims.userId NEW.id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER set_user_id_on_insert
AFTER INSERT ON "user"
FOR EACH ROW
EXECUTE PROCEDURE after_user_insert();
搜索了很多,老实说,我想我可能找不到任何东西,因为我缺少正确的术语来找到我需要找到的东西。
不仅希望帮助您解决这个特定问题,还希望为需要特权的来宾用户提供有关政策的任何相关建议。
语境:
这些是相关的表格和功能
CREATE TYPE "user_role" AS ENUM (
'customer',
'partner',
'admin'
);
CREATE TABLE "user" (
"id" uuid UNIQUE PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(),
"first_name" varchar NOT NULL,
"last_name" varchar NOT NULL,
"email" text UNIQUE NOT NULL,
"role" user_role NOT NULL DEFAULT 'customer',
"created_at" timestamp NOT NULL DEFAULT NOW(),
"updated_at" timestamp NOT NULL DEFAULT NOW()
);
CREATE FUNCTION current_user_id() RETURNS uuid AS $$
SELECT nullif(current_setting('jwt.claims.userId', true), '')::uuid;
$$ LANGUAGE SQL stable;
CREATE FUNCTION current_user_role() RETURNS user_role AS $$
SELECT nullif(current_setting('jwt.claims.role', true), '')::user_role;
$$ LANGUAGE SQL stable
RLS 限制SELECT
为表的id
列user
匹配的行current_setting('jwt.claims.userId')
。
这是由 Postgraphile 先前设置的,如此处所示 ( https://www.graphile.org/postgraphile/security/ )。
我想到的一种可能的解决方法是这样,但由于明显的角色提升,我不知道这是否会导致某种漏洞:
CREATE OR REPLACE FUNCTION after_user_insert()
RETURNS TRIGGER AS $$
BEGIN
SET LOCAL jwt.claims.role TO "customer";
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION before_user_insert()
RETURNS TRIGGER AS $$
BEGIN
SET LOCAL jwt.claims.role TO "admin";
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER before_insert
BEFORE INSERT ON "user"
FOR EACH ROW
EXECUTE PROCEDURE before_user_insert();
CREATE TRIGGER after_insert
AFTER INSERT ON "user"
FOR EACH ROW
EXECUTE PROCEDURE after_user_insert();