PostGraphile НЕ рекомендует гранты SELECT на уровне столбца , вместо этого рекомендует
разделить ваши проблемы на несколько таблиц и использовать функцию отношения один-к-одному, чтобы связать их .
Теперь я хочу, чтобы в моей таблице users
было поле role
, к которому может обращаться role_admin
, но не role_consumer
. На основании приведенной выше рекомендации я создал две таблицы. Таблица users
(в схеме publi c) содержит все поля, которые могут видеть обе роли, а user_accounts
(в частной схеме) содержит поле role
, которое должно видеть только role_admin
. Поле role
добавляется к типу user
GraphQL через вычисляемые столбцы.
CREATE SCHEMA demo_public;
CREATE SCHEMA demo_private;
/* users table*/
CREATE TABLE demo_public.users (
user_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
);
/* user_accounts */
CREATE TABLE demo_private.user_accounts (
user_id INT PRIMARY KEY REFERENCES demo_public.users (user_id) ON DELETE CASCADE,
role text not null default 'role_consumer',
);
/* role as computed column */
CREATE FUNCTION demo_public.users_role
(
u demo_public.users
)
RETURNS TEXT as $$
<code>
$$ LANGUAGE SQL STRICT STABLE;
Теперь в основном у меня есть два зелья для установки разрешений.
1) Первый вариант - использовать безопасность на уровне таблицы. IOW, чтобы предоставить выборочный доступ к таблице user_accounts
ТОЛЬКО role_admin
.
GRANT SELECT ON TABLE demo_private.user_accounts TO role_admin;
GRANT EXECUTE ON FUNCTION demo_public.users_role(demo_public.users) TO role_admin;
ALTER TABLE demo_private.user_accounts ENABLE ROW LEVEL SECURITY;
CREATE POLICY select_any_user_accounts ON demo_private.user_accounts FOR SELECT TO role_admin using (true);
Проблема с этим подходом состоит в том, что когда role_consumer
запускает запрос, который содержит role
поле
{
me {
firstname
role
}
}
Приведенный выше запрос возвращает ошибку. Это не хорошо, так как ошибка влияет на весь результат, скрывая результат других родственных полей.
2) Другой вариант - использовать защиту на уровне строк помимо уровня таблицы; IOW на уровне таблицы, чтобы предоставить выборочный доступ в таблице user_accounts
обоим role_admin
и role_consumer
, но на уровне строк разрешить только администраторам доступ к строкам user_accounts
.
GRANT USAGE ON SCHEMA demo_private TO role_consumer;
GRANT SELECT ON TABLE demo_private.user_accounts TO role_consumer;
GRANT EXECUTE ON FUNCTION demo_public.users_role(demo_public.users) TO role_consumer;
ALTER TABLE demo_private.user_accounts ENABLE ROW LEVEL SECURITY;
CREATE POLICY select_user_accounts ON demo_private.user_accounts FOR SELECT
USING ('role_admin' = nullif(current_setting('role', true), ''));
Теперь, если пользователь с consumer_role
запускает вышеупомянутый запрос, поле role
будет нулевым, не затрагивая его родственные поля. Но два вопроса:
Должны ли мы всегда избегать ошибок, чтобы предотвратить их влияние на своих братьев и сестер?
Если да, должны ли мы всегда обрабатывать вещи в строке Уровень и никогда только на уровне таблицы?