Опциите включват:
-
Когато отворите връзка,
CREATE TEMPORARY TABLE current_app_user(username text); INSERT INTO current_app_user(username) VALUES ('the_user');
. След това във вашето задействанеSELECT username FROM current_app_user
за да получите текущото потребителско име, вероятно като подзаявка. -
В
postgresql.conf
създайте запис за персонализиран GUC катоmy_app.username = 'unknown';
. Всеки път, когато създавате връзка, стартирайтеSET my_app.username = 'the_user';
. След това в тригери използвайтеcurrent_setting('my_app.username')
функция за получаване на стойността. На практика злоупотребявате с GUC машината, за да предоставите променливи на сесията. Прочетете документацията, подходяща за версията на вашия сървър, тъй като персонализираните GUC са променени в 9.2 . -
Настройте приложението си така, че да има роли на база данни за всеки потребител на приложението.
SET ROLE
на този потребител, преди да свършите работа. Това не само ви позволява да използвате вграденияcurrent_user
подобна на променлива функция заSELECT current_user;
, също така ви позволява да наложите сигурност в базата данни . Вижте този въпрос. Можете да влезете директно като потребител, вместо да използватеSET ROLE
, но това затруднява обединяването на връзки.
И в двата случая, когато обединявате връзки, трябва да внимавате да DISCARD ALL;
когато върнете връзка към пула. (Въпреки че не е документирано, че прави това, DISCARD ALL
прави RESET ROLE
).
Обща настройка за демонстрации:
CREATE TABLE tg_demo(blah text);
INSERT INTO tg_demo(blah) VALUES ('spam'),('eggs');
-- Placeholder; will be replaced by demo functions
CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
SELECT 'unknown';
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION tg_demo_trigger() RETURNS trigger AS $$
BEGIN
RAISE NOTICE 'Current user is: %',get_app_user();
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tg_demo_tg
AFTER INSERT OR UPDATE OR DELETE ON tg_demo
FOR EACH ROW EXECUTE PROCEDURE tg_demo_trigger();
Използване на GUC:
- В
CUSTOMIZED OPTIONS
раздел наpostgresql.conf
, добавете ред катоmyapp.username = 'unknown_user'
. На версии на PostgreSQL, по-стари от 9.2, също трябва да зададетеcustom_variable_classes = 'myapp'
. - Рестартирайте PostgreSQL. Вече ще можете да
SHOW myapp.username
и получете стойносттаunknown_user
.
Сега можете да използвате SET myapp.username = 'the_user';
когато установите връзка, или алтернативно SET LOCAL myapp.username = 'the_user';
след BEGIN
извеждане на транзакция, ако искате тя да бъде локална за транзакция, което е удобно за обединени връзки.
get_app_user
дефиниция на функцията:
CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
SELECT current_setting('myapp.username');
$$ LANGUAGE sql;
Демо с помощта на SET LOCAL
за локално текущо потребителско име за транзакция:
regress=> BEGIN;
BEGIN
regress=> SET LOCAL myapp.username = 'test_user';
SET
regress=> INSERT INTO tg_demo(blah) VALUES ('42');
NOTICE: Current user is: test_user
INSERT 0 1
regress=> COMMIT;
COMMIT
regress=> SHOW myapp.username;
myapp.username
----------------
unknown_user
(1 row)
Ако използвате SET
вместо SET LOCAL
настройката няма да бъде възстановена по време на записване/връщане назад, така че е постоянна през цялата сесия. Все още се нулира чрез DISCARD ALL
:
regress=> SET myapp.username = 'test';
SET
regress=> SHOW myapp.username;
myapp.username
----------------
test
(1 row)
regress=> DISCARD ALL;
DISCARD ALL
regress=> SHOW myapp.username;
myapp.username
----------------
unknown_user
(1 row)
Също така имайте предвид, че не можете да използвате SET
или SET LOCAL
с параметри за свързване от страна на сървъра. Ако искате да използвате параметри за свързване („подготвени изявления“), помислете за използването на функционалния формуляр set_config(...)
. Вижте функциите за системно администриране
Използване на временна таблица
Този подход изисква използването на тригер (или помощна функция, извикана от тригер, за предпочитане), която се опитва да прочете стойност от временна таблица, която всяка сесия трябва да има. Ако временната таблица не може да бъде намерена, се предоставя стойност по подразбиране. Това вероятно ще бъде малко бавно . Тествайте внимателно.
get_app_user()
определение:
CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
DECLARE
cur_user text;
BEGIN
BEGIN
cur_user := (SELECT username FROM current_app_user);
EXCEPTION WHEN undefined_table THEN
cur_user := 'unknown_user';
END;
RETURN cur_user;
END;
$$ LANGUAGE plpgsql VOLATILE;
Демо:
regress=> CREATE TEMPORARY TABLE current_app_user(username text);
CREATE TABLE
regress=> INSERT INTO current_app_user(username) VALUES ('testuser');
INSERT 0 1
regress=> INSERT INTO tg_demo(blah) VALUES ('42');
NOTICE: Current user is: testuser
INSERT 0 1
regress=> DISCARD ALL;
DISCARD ALL
regress=> INSERT INTO tg_demo(blah) VALUES ('42');
NOTICE: Current user is: unknown_user
INSERT 0 1
Променливи за защитена сесия
Има също така предложение за добавяне на "променливи за защитена сесия" към PostgreSQL. Това са малко като пакетни променливи. От PostgreSQL 12 функцията не е включена, но внимавайте и говорете в списъка с хакери, ако това е нещо, от което се нуждаете.
Разширени:ваше собствено разширение със споделена памет
За напреднали приложения можете дори да имате собствено разширение C да регистрира споделена област на паметта и да комуникира между бекендове, използвайки извиквания на C функции, които четат/записват стойности в DSA сегмент. Вижте примерите за програмиране на PostgreSQL за подробности. Ще ви трябват знания, време и търпение по C.