powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / раздача прав доступа на конкретные строки таблиц
19 сообщений из 19, страница 1 из 1
раздача прав доступа на конкретные строки таблиц
    #33051573
джанкер
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вот что в итоге получилось:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE TABLE acl
(
  group_id int4 NOT NULL, 	-- id группы
  obj_id int4 NOT NULL,   	-- id объекта (таблицы)
  access_type int4 NOT NULL,	-- тип доступа (1 - VIEW, 2 - INSERT, 3 - UPDATE, 4 - DELETE)
  grant_perm int4		-- Право (0 или NULL - Нет, 1 - своё, 2 - группа, 3 - 

родительская группа,  4  - всё
) 

CREATE TABLE objects
(
  id int4 NOT NULL,
  name varchar
) 
Права назначаются группам
Группы могут иметь 2 уровня вложенности

Во всех таблицах присутствует поле author_id
Для каждой таблыцы есть триггер который проверяет право на требуемый уровень доступа

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
CREATE TRIGGER __trig__trade_partners_acl_check
  BEFORE INSERT OR UPDATE OR DELETE
  ON __trade_partners
  FOR EACH ROW
  EXECUTE PROCEDURE __main_trig_acl_check();

CREATE OR REPLACE FUNCTION __main_trig_acl_check()
  RETURNS "trigger" AS
$BODY$DECLARE
	_user	VARCHAR;
BEGIN
	IF TG_OP = 'INSERT' THEN
		IF __proc_main_acl_insert_get(TG_RELNAME::varchar) THEN
			NEW.author_id = (SELECT id FROM __main_users WHERE nick = session_user);
			RETURN NEW;
		ELSE
			_user = session_user;
			RAISE EXCEPTION 'INSERT action in table "%" for user "%" not permitted',TG_RELNAME,_user;
			RETURN NULL;
		END IF;
	ELSEIF TG_OP = 'UPDATE' THEN
		IF (SELECT OLD.author_id IN (SELECT * FROM __proc_main_acl_users_get(TG_RELNAME::varchar, 3 ))) THEN
			RETURN NEW;
		ELSE
			_user = session_user;
			RAISE EXCEPTION 'UPDATE action in table "%" for user "%" not permitted',TG_RELNAME,_user;
			RETURN NULL;
		END IF;
	ELSEIF TG_OP = 'DELETE' THEN
		IF (SELECT OLD.author_id IN (SELECT * FROM __proc_main_acl_users_get(TG_RELNAME::varchar, 4 ))) THEN
			RETURN OLD;
		ELSE
			_user = session_user;
			RAISE EXCEPTION 'DELETE action in table "%" for user "%" not permitted',TG_RELNAME,_user;
			RETURN NULL;
		END IF;
	END IF;
END;$BODY$
  LANGUAGE 'plpgsql' VOLATILE;

При выборке данных селектом используется условие
Код: plaintext
...WHERE author_id IN (SELECT * FROM __proc_main_acl_users_get(таблица,доступ)



время выполнения селектов увеличилось на ~120мс независимо от количества записей в таблицах
время выполнения инсертов,апдейтов и делитов измерю позже

как вам такой вариант решения проблемы?
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33051761
фффф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
джанкервремя выполнения селектов увеличилось на ~120мс независимо от количества записей в таблицах
Очень интересно. А какое максимальное кол-во записей в acl и objects в тесте?
У нас похожая схема проверки построчного доступа (только не на PostgreSQL) напрочь убивает некоторые запросы на больших таблицах. При update/insert/delete быстро проверяются права на небольшое число строк, а вот хорошей скорости select непросто достичь. Частичные/функциональные индексы используются?
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33051964
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 джанкер: киньте пожалуйста explain analyze для нескольких select-ов

2 all: вот что обсуждалось ранее
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33053392
Фотография vadiminfo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Лучше мне кажется в Оракле. Есть специальные средства - Тщательный контроль доступа. Там просто динамически в любой запрос к табле подставляется WHERE с условием, которое пожелал разработчик.
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33053887
фффф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В Sybase ASE тоже аналогичная штучка есть: Row-level access control, но за отдельные деньги. Подозреваю что у Оракла тоже.
И всё опять же упирается в функцию проверки прав во WHERE - как напишешь, с такой скоростью и будет работать. Конечно для простой системы, где все пользователи должны видеть только свои данные всё просто.
Но когда начинаешь усложнять проверку (проверять вхождение пользователя в группы например) - чтобы не тормозило надо очень постараться. А при большом числе пользователей в системе уровня предприятия это просто необходимо, иначе ни о какой безопасности речь не идет - никакой админ не согласится целыми днями давать/отбирать права лично каждому - он скорее всего даст кучу лишних прав чтобы от него отвязались.
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33053932
Сахават Юсифов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если это была бы хорошей идеей, то она давно была бы встроена в SQL и рекомендавалась бы особо.
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33054349
Фотография vadiminfo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
> Если это была бы хорошей идеей, то она давно была бы встроена в SQL и рекомендавалась бы особо
А Вы смотрите на это как на динамическме представления, которые в зависмости от юзера привистовыают к табле, в каком бы она запросе не была where c усовием, которое прописал разработчик. Представления встроены в SQL . Но их может понадобиться туча для аналогичного. Да и приложение переделывать во многих местах.

Кроме того, раз уже, как минимум, две СУБД это поддерживают, то, скорее всего, это не так уж и плохо.
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33054409
Сахават Юсифов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я то , в принципе, не против. чего только не делаешь для упрощения структуры БД. Просто SQL и Update - понятия не очень совместимые. Insert еще куда не шла. Как OLAP предназначен для многомерного анализа, так и SQL для плоского. Должен быть дополнительный слой работы с полями и записями. Те.ввод и изменения данных должны происходить в другой системе, а результаты передаватся в SQL-OLAP для плоских и многомерных отчетов.
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33054733
джанкер
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
после праздников выложу EXPLAIN ANALYZE
пока могу сказать только
~12000 юзеров
~300 групп
~60000 записей в acl

на скорость выборки из таблицы 9 млн записей не особо влияет
в сложных запросах на маленких таблицах тоже

в общем точные цифры скоро будут
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33054749
Фотография vadiminfo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сахават Юсифов
Просто SQL и Update - понятия не очень совместимые. Insert еще куда не шла.

Не совсем ясна мысль. В свете того, что SQL - язык БД, а Update - прямая обязанность языка БД. Кроме того, Update можно воспринимать как delete и Insert. Поэтому они тоже тада должны выглядеть как не очень совместимые с SQL. Что тада от него останется? Только чтение?
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33054865
Подобная тема уже обсуждалась здесь

Сам я придерживаюсь такой концепции: ACL для РСУБД не есть хорошо. Действительно это намного медленне чем RWD/Unix

Когда-то давно была написана статья В ней тоже разделены понятия ACL и RWD. А в конце загадочные строки "Продолжение следует! Далее будут: объединение схем RWD и ACL"

Я до сих пор не понял, как можно (и возможно ли вообще?) объединить эти две модели так, чтоб получить скорость от RWD/Unix и удобства управления правами от ACL. Если кто-то имеет информацию о подобном миксе отзовитесь пожалуйста!
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33057122
джанкер
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
EXPLAIN ANALYZE
SELECT g.id,g.parent_id,g.group,g.name,SUM(oi.incoming_qty) - SUM(oi.outgoing_qty) AS "qty",mu.id AS "mu_id",mu.name AS "mu_name"
FROM __trade_goods g
LEFT OUTER JOIN __trade_operations_items oi on g.id = oi.goods_id AND oi.storage_id =  3 
	AND oi.author_id IN (SELECT * FROM __proc_main_acl_users_get('__trade_operations_items', 1 ))			
LEFT OUTER JOIN __trade_var_of_measuring_units mu ON mu.id = g.measuring_unit_id
	AND mu.author_id IN (SELECT * FROM __proc_main_acl_users_get('__trade_var_of_measuring_units', 1 ))
WHERE g.parent_id =  4065 
	AND g.author_id IN (SELECT * FROM __proc_main_acl_users_get('__trade_goods', 1 ))
GROUP BY g.id, g.name,g.group,g.parent_id,mu.id,mu.name
ORDER BY g.group DESC, g.name ASC;


"Sort  (cost=134.09..134.15 rows=22 width=90) (actual time=1862.000..1872.000 rows=3906 loops=1)"
"  Sort Key: g."group", g.name"
"  ->  HashAggregate  (cost=133.43..133.60 rows=22 width=90) (actual time=1512.000..1532.000 rows=3906 loops=1)"
"        ->  Hash Join  (cost=130.77..132.99 rows=22 width=90) (actual time=1412.000..1462.000 rows=3906 loops=1)"
"              Hash Cond: ("outer".__proc_main_acl_users_get = "inner".author_id)"
"              ->  HashAggregate  (cost=15.00..15.00 rows=200 width=4) (actual time=391.000..421.000 rows=13770 loops=1)"
"                    ->  Function Scan on __proc_main_acl_users_get  (cost=0.00..12.50 rows=1000 width=4) (actual time=270.000..300.000 rows=13770 loops=1)"
"              ->  Hash  (cost=115.72..115.72 rows=22 width=94) (actual time=961.000..961.000 rows=0 loops=1)"
"                    ->  Hash Left Join  (cost=32.93..115.72 rows=22 width=94) (actual time=821.000..931.000 rows=3906 loops=1)"
"                          Hash Cond: ("outer".measuring_unit_id = "inner".id)"
"                          ->  Hash Left Join  (cost=16.90..99.57 rows=22 width=75) (actual time=401.000..451.000 rows=3906 loops=1)"
"                                Hash Cond: ("outer".id = "inner".goods_id)"
"                                ->  Index Scan using __idx_group_parent_id on __trade_goods g  (cost=0.00..82.55 rows=22 width=49) (actual time=0.000..20.000 rows=3906 loops=1)"
"                                      Index Cond: (parent_id = 4065)"
"                                ->  Hash  (cost=16.90..16.90 rows=1 width=30) (actual time=401.000..401.000 rows=0 loops=1)"
"                                      ->  Seq Scan on __trade_operations_items oi  (cost=15.00..16.90 rows=1 width=30) (actual time=401.000..401.000 rows=5 loops=1)"
"                                            Filter: ((storage_id = 3) AND (hashed subplan))"
"                                            SubPlan"
"                                              ->  Function Scan on __proc_main_acl_users_get  (cost=0.00..12.50 rows=1000 width=4) (actual time=271.000..331.000 rows=13770 loops=1)"
"                          ->  Hash  (cost=16.02..16.02 rows=1 width=23) (actual time=420.000..420.000 rows=0 loops=1)"
"                                ->  Seq Scan on __trade_var_of_measuring_units mu  (cost=15.00..16.02 rows=1 width=23) (actual time=420.000..420.000 rows=2 loops=1)"
"                                      Filter: (hashed subplan)"
"                                      SubPlan"
"                                        ->  Function Scan on __proc_main_acl_users_get  (cost=0.00..12.50 rows=1000 width=4) (actual time=280.000..330.000 rows=13770 loops=1)"
"Total runtime: 1892.000 ms"


EXPLAIN ANALYZE
SELECT * FROM __main_test_table
WHERE id BETWEEN  7000000  AND  7211100  
AND author_id IN (SELECT * FROM __proc_main_acl_users_get('__trade_operations_items', 1 ))

"Hash Join  (cost=15.50..109175.46 rows=27188 width=161) (actual time=491.000..3885.000 rows=211101 loops=1)"
"  Hash Cond: ("outer".author_id = "inner".__proc_main_acl_users_get)"
"  ->  Index Scan using __idx_main_test_table_pkey on __main_test_table  (cost=0.00..108752.14 rows=27188 width=161) (actual time=0.000..1640.000 rows=211101 loops=1)"
"        Index Cond: ((id >= 7000000) AND (id <= 7211100))"
"  ->  Hash  (cost=15.00..15.00 rows=200 width=4) (actual time=491.000..491.000 rows=0 loops=1)"
"        ->  HashAggregate  (cost=15.00..15.00 rows=200 width=4) (actual time=390.000..451.000 rows=13770 loops=1)"
"              ->  Function Scan on __proc_main_acl_users_get  (cost=0.00..12.50 rows=1000 width=4) (actual time=270.000..340.000 rows=13770 loops=1)"
"Total runtime: 4657.000 ms"
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33059261
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
джанкер
Код: plaintext
1.
2.
3.
4.
"->  Hash  (cost=16.02..16.02 rows=1 width=23) (actual time=420.000..420.000 rows=0 loops=1)"
"  ->  Seq Scan on __trade_var_of_measuring_units mu  (cost=15.00..16.02 rows=1 width=23) (actual time=420.000..420.000 rows=2 loops=1)"
"  Filter: (hashed subplan)"
"  SubPlan"
"   ->  Function Scan on __proc_main_acl_users_get  (cost=0.00..12.50 rows=1000 width=4) (actual time=280.000..330.000 rows=13770 loops=1)"
Четыре десятых секунды на проверку прав на две строки (из таблицы mu). :-( Гораздо быстрее это вроде бы сделать с помощью аналогичной функции с дополнительным аргументом author_id: select ... from __trade_var_of_measuring_units mu where exists ( select 1 from __proc_main_acl_user_get('__trade_var_of_measuring_units',1,mu.author_id)). Думаю, что таким образом первый запрос можно ускорить с 1.9 до 1.1 секунды.

Может быть вообще получится вместо функций __proc_main_acl_users_get, __proc_main_acl_user_get сделать view. Тогда постгрес будет сам выбирать план выполнения: "а-ля users_get" или "а-ля user_get".
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33059602
Фотография BusyMan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
"раздача прав доступа на конкретные строки таблиц" - не соответствует содержанию. Т.к. в вашем варианте, как мне кажется, вы разделяете доступ к строкам созданным тем же человеком. А если надо смотреть чужие строки... Как вы собираетесь это показать?

Почему вы все не заменить на:
Код: plaintext
... WHERE author_id = (SELECT id FROM __main_users WHERE nick = session_user);
???
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33059911
джанкер
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
2LeXa NalBat:
LeXa NalBat
Четыре десятых секунды на проверку прав на две строки (из таблицы mu). :-( Гораздо быстрее это вроде бы сделать с помощью аналогичной функции с дополнительным аргументом author_id: select ... from __trade_var_of_measuring_units mu where exists ( select 1 from __proc_main_acl_user_get('__trade_var_of_measuring_units',1,mu.author_id)). Думаю, что таким образом первый запрос можно ускорить с 1.9 до 1.1 секунды.


попробую поэкпериментировать с этим :))

LeXa NalBat
Может быть вообще получится вместо функций __proc_main_acl_users_get, __proc_main_acl_user_get сделать view. Тогда постгрес будет сам выбирать план выполнения: "а-ля users_get" или "а-ля user_get".

что то мне не представляется возможным написание такой вьюхи...

вот как выглядит __proc_main_acl_users_get:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
CREATE OR REPLACE FUNCTION __proc_main_acl_users_get("varchar", int4)
  RETURNS SETOF int4 AS
$BODY$DECLARE
	_table_name		ALIAS FOR $ 1 ;
	_access_type		ALIAS FOR $ 2 ;
	_group_id		INT4;
	_parent_group_id	INT4;
	_obj_id			INT4;
	_grant_perm		INT4;
	_row			RECORD;
BEGIN
	_obj_id = (SELECT id FROM objects WHERE name = _table_name);
	_group_id = (SELECT parent_id FROM __main_users WHERE nick = session_user);

	_grant_perm = (SELECT grant_perm FROM acl
		WHERE obj_id = _obj_id
		AND group_id = _group_id
		AND access_type = _access_type);

	IF _grant_perm =  0  THEN -- нет доступа
	ELSEIF _grant_perm =  1  THEN -- своё
		RETURN NEXT (SELECT id FROM __main_users WHERE nick = session_user);
	ELSEIF _grant_perm =  2  THEN -- группа
		FOR _row IN SELECT id FROM __main_users WHERE parent_id = _group_id AND "group" = FALSE LOOP
			RETURN NEXT _row.id;
		END LOOP;
	ELSEIF _grant_perm =  3  THEN -- родительская группа
		_parent_group_id = (SELECT parent_id FROM __main_users WHERE id = _group_id);

		FOR _row IN SELECT __proc_main_acl_users_id_get AS "id" FROM __proc_main_acl_users_id_get(_parent_group_id) LOOP
			RETURN NEXT _row.id;
		END LOOP;
	ELSEIF _grant_perm =  4  THEN -- всё
		RETURN NEXT NULL;
		FOR _row IN SELECT id FROM __main_users WHERE "group" = FALSE LOOP
			RETURN NEXT _row.id;
		END LOOP;
	END IF;

	RETURN;

END;$BODY$
  LANGUAGE 'plpgsql' STABLE SECURITY DEFINER;



2BusyMan:
BusyManПочему вы все не заменить на:
Код: plaintext
... WHERE author_id = (SELECT id FROM __main_users WHERE nick = session_user);
???

в таком случае юзер увидит только свои записи
а надо чтобы он имел возможность увидеть записи членов своей группы, членов родительской группы или же записи всех пользователей
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33060070
Фотография BusyMan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Невозможно вот так вот строго разбить пользователей на группы...
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #33068273
strizh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А что вы делаете, если триггер выдает raise exception для операции update в ситуации, когда этот update вызван констрейнтом на справочник с on update cascade ? Да, ссылочная целостность соблюдется, но если нужно просто поменять какой-нить код в справочнике, то для этого надо быть юзером с ПОЛНЫМИ правами, а не только правами на изменяемую запись в справочнике.
Ну ладно - справочники, можно жить с тем, что их только админы и меняют. А если это таблицы системы документооборота с цепочечными схемами обработки документов ?
И тогда у юзеров будут вопросы типа
"Шеф сказал мне подправить номер моего договора, а я не могу, пишет, шо нет прав на обновление таблицы ПлановаяПрибыльПоКонтрактам... А ШО ЭТО за таблица ?"
Юзер (и, возможно, его шеф) и знать не знает, что такая таблица где-то там ведется, а тут ему такое вываливает ... :)
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
раздача прав доступа на конкретные строки таблиц
    #35734886
assa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
инфо к размышлению

просматривая все по теме строчных прав наткнулся на эту старую тему. И посмотрел, что же творит сам PostgreSQL - т.е. где он хранит права.
таки посмотрев в скрипт вью
Код: plaintext
information_schema.table_privileges
легко заметить, что права постгрес хранит в одном поле таблички
Код: plaintext
pg_class.relacl
(правда-правда. Весь акл - в одном поле).

Одной таблички ему хватает ибо тип поля - массив типа
Код: plaintext
aclitem[]
есть пара ф-й для работы с типом:
Код: plaintext
aclcontains(c.relacl, makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
- вот кусок из вьюхи.


вот думаю: дает ди такое хранение какие-то преимущества? С одной - джойнится с кросс таблицей прав не надо - она вся (джойновая часть) лежит в поле. С другой - можно даже какими-то функциональными индексами попытаться обвешаться по такому полю (только вот какими надо?) и его вхождению...
...
Рейтинг: 0 / 0
раздача прав доступа на конкретные строки таблиц
    #35735097
_мод
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
джанкеркак вам такой вариант решения проблемы?
Никак.
Проверять надо только право на чтение юзером объекта. Для этого автоматом (на основе классификации юзеров и объектов) строится таблица доступа юзер-объект-уровень доступа. Уровень доступа - понятие семантическое и зависит от типа объекта.
А все изменения данных - это функции, права на которые раздаются отдельно.
...
Рейтинг: 0 / 0
19 сообщений из 19, страница 1 из 1
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / раздача прав доступа на конкретные строки таблиц
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]