Zu den Optionen gehören:
-
Wenn Sie eine Verbindung öffnen,
CREATE TEMPORARY TABLE current_app_user(username text); INSERT INTO current_app_user(username) VALUES ('the_user');
. Dann in Ihrem AuslöserSELECT username FROM current_app_user
um den aktuellen Benutzernamen zu erhalten, möglicherweise als Unterabfrage. -
In
postgresql.conf
Erstellen Sie einen Eintrag für einen benutzerdefinierten GUC wiemy_app.username = 'unknown';
. Immer wenn Sie eine Verbindung erstellen, führen SieSET my_app.username = 'the_user';
aus . Verwenden Sie dann in Triggern diecurrent_setting('my_app.username')
Funktion, um den Wert zu erhalten. Tatsächlich missbrauchen Sie die GUC-Maschinerie, um Sitzungsvariablen bereitzustellen. Lesen Sie die Ihrer Serverversion entsprechende Dokumentation, da sich benutzerdefinierte GUCs in 9.2 geändert haben . -
Passen Sie Ihre Anwendung so an, dass sie Datenbankrollen für jeden Anwendungsbenutzer hat.
SET ROLE
an diesen Benutzer, bevor Sie mit der Arbeit beginnen. Dadurch können Sie nicht nur den eingebautencurrent_user
verwenden variablenähnliche Funktion zuSELECT current_user;
, ermöglicht es Ihnen auch, Sicherheit in der Datenbank zu erzwingen . Siehe diese Frage. Sie könnten sich direkt als Benutzer anmelden, anstattSET ROLE
zu verwenden , aber das erschwert das Verbindungspooling.
In allen drei Fällen, in denen Sie Verbindungen zusammenfassen, müssen Sie darauf achten, DISCARD ALL;
wenn Sie eine Verbindung zum Pool zurückgeben. (Obwohl dies nicht dokumentiert ist, DISCARD ALL
führt eine RESET ROLE
aus ).
Allgemeines Setup für Demos:
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();
Verwenden eines GUC:
- In den
CUSTOMIZED OPTIONS
Abschnitt vonpostgresql.conf
, fügen Sie eine Zeile wiemyapp.username = 'unknown_user'
hinzu . Bei PostgreSQL-Versionen älter als 9.2 müssen Sie außerdemcustom_variable_classes = 'myapp'
setzen . - Starten Sie PostgreSQL neu. Sie können jetzt
SHOW myapp.username
und erhalten Sie den Wertunknown_user
.
Jetzt können Sie SET myapp.username = 'the_user';
verwenden wenn Sie eine Verbindung herstellen, oder alternativ SET LOCAL myapp.username = 'the_user';
nach BEGIN
ning einer Transaktion, wenn Sie möchten, dass sie transaktionslokal ist, was praktisch für gepoolte Verbindungen ist.
Der get_app_user
Funktionsdefinition:
CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
SELECT current_setting('myapp.username');
$$ LANGUAGE sql;
Demo mit SET LOCAL
für transaktionslokalen aktuellen Benutzernamen:
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)
Wenn Sie SET
verwenden statt SET LOCAL
Die Einstellung wird beim Commit/Rollback nicht zurückgesetzt, sodass sie über die gesamte Sitzung hinweg bestehen bleibt. Es wird immer noch durch DISCARD ALL
zurückgesetzt :
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)
Beachten Sie auch, dass Sie SET
nicht verwenden können oder SET LOCAL
mit serverseitigen Bindungsparametern. Wenn Sie Bindungsparameter ("vorbereitete Anweisungen") verwenden möchten, ziehen Sie die Verwendung der Funktionsform set_config(...)
in Betracht . Siehe Systemverwaltungsfunktionen
Eine temporäre Tabelle verwenden
Dieser Ansatz erfordert die Verwendung eines Triggers (oder vorzugsweise einer Hilfsfunktion, die von einem Trigger aufgerufen wird), der versucht, einen Wert aus einer temporären Tabelle zu lesen, den jede Sitzung haben sollte. Wenn die temporäre Tabelle nicht gefunden werden kann, wird ein Standardwert bereitgestellt. Dies ist wahrscheinlich etwas langsam . Testen Sie sorgfältig.
Der get_app_user()
Definition:
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
Sichere Sitzungsvariablen
Es gibt auch einen Vorschlag, PostgreSQL "sichere Sitzungsvariablen" hinzuzufügen. Diese sind ein bisschen wie Paketvariablen. Ab PostgreSQL 12 ist diese Funktion nicht mehr enthalten, aber halten Sie Ausschau und melden Sie sich auf der Hackerliste, wenn Sie dies benötigen.
Erweitert:Ihre eigene Erweiterung mit gemeinsamem Speicherbereich
Für fortgeschrittene Anwendungen können Sie sogar Ihre eigene C-Erweiterung einen gemeinsam genutzten Speicherbereich registrieren lassen und mithilfe von C-Funktionsaufrufen, die Werte in einem DSA-Segment lesen/schreiben, zwischen Backends kommunizieren. Einzelheiten finden Sie in den PostgreSQL-Programmierbeispielen. Sie benötigen C-Kenntnisse, Zeit und Geduld.