Opcje obejmują:
-
Po otwarciu połączenia
CREATE TEMPORARY TABLE current_app_user(username text); INSERT INTO current_app_user(username) VALUES ('the_user');
. Następnie w wyzwalaczuSELECT username FROM current_app_user
aby uzyskać aktualną nazwę użytkownika, prawdopodobnie jako podzapytanie. -
W
postgresql.conf
utwórz wpis dla niestandardowego GUC, takiego jakmy_app.username = 'unknown';
. Za każdym razem, gdy tworzysz połączenie, uruchomSET my_app.username = 'the_user';
. Następnie w wyzwalaczach użyjcurrent_setting('my_app.username')
funkcja do uzyskania wartości. W rzeczywistości nadużywasz maszynerii GUC, aby zapewnić zmienne sesji. Przeczytaj dokumentację odpowiednią dla Twojej wersji serwera, ponieważ niestandardowe GUC zmieniły się w wersji 9.2 . -
Dostosuj swoją aplikację tak, aby miała role bazy danych dla każdego użytkownika aplikacji.
SET ROLE
do tego użytkownika przed wykonaniem pracy. Pozwala to nie tylko na użycie wbudowanegocurrent_user
funkcja podobna do zmiennej doSELECT current_user;
, umożliwia także wymuszanie bezpieczeństwa w bazie danych . Zobacz to pytanie. Możesz zalogować się bezpośrednio jako użytkownik zamiast używaćSET ROLE
, ale to zwykle utrudnia łączenie połączeń.
W obu trzech przypadkach puli połączeń musisz uważać, aby DISCARD ALL;
po zwróceniu połączenia do puli. (Chociaż nie jest to udokumentowane, DISCARD ALL
wykonuje RESET ROLE
).
Wspólna konfiguracja dla wersji demonstracyjnych:
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();
Korzystanie z GUC:
- W
CUSTOMIZED OPTIONS
sekcjapostgresql.conf
, dodaj wiersz, taki jakmyapp.username = 'unknown_user'
. W wersjach PostgreSQL starszych niż 9.2 musisz również ustawićcustom_variable_classes = 'myapp'
. - Uruchom ponownie PostgreSQL. Teraz będziesz mógł
SHOW myapp.username
i uzyskaj wartośćunknown_user
.
Teraz możesz użyć SET myapp.username = 'the_user';
podczas nawiązywania połączenia lub alternatywnie SET LOCAL myapp.username = 'the_user';
po BEGIN
transakcji, jeśli chcesz, aby była lokalna dla transakcji, co jest wygodne w przypadku połączeń w puli.
get_app_user
definicja funkcji:
CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
SELECT current_setting('myapp.username');
$$ LANGUAGE sql;
Demo za pomocą SET LOCAL
dla bieżącej nazwy użytkownika dla transakcji:
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)
Jeśli używasz SET
zamiast SET LOCAL
ustawienie nie zostanie przywrócone w czasie zatwierdzenia/wycofania, więc jest trwałe w całej sesji. Nadal jest resetowany przez 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)
Pamiętaj też, że nie możesz użyć SET
lub SET LOCAL
z parametrami wiązania po stronie serwera. Jeśli chcesz użyć parametrów wiązania ("przygotowanych instrukcji"), rozważ użycie formularza funkcji set_config(...)
. Zobacz funkcje administracyjne systemu
Korzystanie z tabeli tymczasowej
To podejście wymaga użycia wyzwalacza (lub funkcji pomocniczej wywoływanej przez wyzwalacz), który próbuje odczytać wartość z tabeli tymczasowej, którą powinna mieć każda sesja. Jeśli nie można znaleźć tabeli tymczasowej, podawana jest wartość domyślna. To prawdopodobnie będzie trochę powolne . Przetestuj dokładnie.
get_app_user()
definicja:
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;
Demo:
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
Bezpieczne zmienne sesji
Istnieje również propozycja dodania "bezpiecznych zmiennych sesji" do PostgreSQL. Przypominają trochę zmienne pakietu. Od PostgreSQL 12 ta funkcja nie została uwzględniona, ale miej oko na listę hakerów, jeśli jest to coś, czego potrzebujesz.
Zaawansowane:własne rozszerzenie ze współdzielonym obszarem pamięci
W przypadku zaawansowanych zastosowań możesz nawet mieć własne rozszerzenie C, które rejestruje obszar pamięci współdzielonej i komunikuje się między backendami za pomocą wywołań funkcji C, które odczytują/zapisują wartości w segmencie DSA. Zobacz przykłady programowania PostgreSQL, aby uzyskać szczegółowe informacje. Będziesz potrzebować wiedzy C, czasu i cierpliwości.