数据库中有 3 个表 - 部门、员工、帐户。一个部门有很多员工。员工包含列
department_id bigint
帐户表包含列 login varchar
、employee_id bigint
,用于将 Postgres 用户(角色)绑定到 Employee 中的行。
我的目标是让用户仅查看和使用
department_id
值与用户相同的 Employee 行。
一定有这样的东西:
CREATE POLICY locale_policy ON employee
TO justuser, operator
USING (department_id =
(SELECT department_id FROM employee WHERE id =
(SELECT employee_id FROM account WHERE login = CURRENT_USER)
)
)
但是由于 Employee 的子查询,它正在提高
infinite recursion detected in policy for relation employee
。
编辑:关系定义为:
create table department(
id serial primary key);
create table employee(
id serial primary key,
department_id int8 not null references department(id));
create table account(
id serial primary key,
login varchar(100) not null unique,
employee_id int8 not null unique references employee(id));
我不知道它有多好,但它对我有用。我找到了一个解决方案,创建一个视图,其中 current_user 的部门 id,然后检查它是否匹配:
CREATE VIEW curr_department AS
(SELECT department_id as id FROM employee WHERE id =
(SELECT employee_id FROM account WHERE login = current_user)
);
CREATE POLICY locale_policy ON employee
TO justuser, operator
USING (department_id =
(SELECT id FROM curr_department)
);
las rexter 不允许创建角色.. http://rextester.com/QDYC6798
create table department(
id serial primary key);
create table employee(
id serial primary key,
department_id int8 not null references department(id));
create table account(
id serial primary key,
login varchar(100) not null unique,
employee_id int8 not null unique references employee(id));
insert into department default values;
insert into department default values;
insert into employee (department_id ) select 1;
insert into employee (department_id ) select 2;
insert into account (login,employee_id) select 'justuser',1;
insert into account (login,employee_id) select 'operator',2;
create role justuser;
create role operator;
set role justuser;
select * from employee;
无法重现。这不是一个答案 - 只是一个格式化的脚本。解决后我会删除它
这是我使用的更简洁的解决方案。我使用
auth
表中的一个单独的用户表来管理用户。从该表中,我使用自定义枚举类型并在 RLS 策略上使用辅助函数。
CREATE TYPE user_role AS enum ('USER', 'ADMIN');
CREATE TABLE users (
id uuid PRIMARY KEY NOT NULL REFERENCES auth.users(id),
name text NOT NULL,
role user_role NOT NULL DEFAULT 'USER'::user_role,
email text UNIQUE NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT timezone('utc'::text, now()),
updated_at timestamp with time zone NOT NULL DEFAULT timezone('utc'::text, now())
);
CREATE OR REPLACE FUNCTION is_admin (user_id UUID)
RETURNS BOOL AS $$
BEGIN
PERFORM
FROM public.users
WHERE id = user_id AND role = 'ADMIN'::user_role;
RETURN FOUND;
END;
$$ LANGUAGE plpgsql SECURITY definer;
CREATE POLICY "Admins can view all users data" ON public.users
FOR SELECT
TO authenticated
USING (is_admin(auth.uid()));
PERFORM
语句用于执行查询而不返回任何结果数据。在本例中,它检查 public.users
表中是否存在行。