Opties zijn onder meer:
-
Wanneer u een verbinding opent,
CREATE TEMPORARY TABLE current_app_user(username text); INSERT INTO current_app_user(username) VALUES ('the_user');
. Dan in je trigger,SELECT username FROM current_app_user
om de huidige gebruikersnaam te krijgen, mogelijk als een subquery. -
In
postgresql.conf
maak een vermelding voor een aangepaste GUC zoalsmy_app.username = 'unknown';
. Telkens wanneer u een verbinding maakt, voert uSET my_app.username = 'the_user';
. uit . Gebruik vervolgens in triggers decurrent_setting('my_app.username')
functie om de waarde te verkrijgen. In feite misbruik je de GUC-machinerie om sessievariabelen te leveren. Lees de documentatie die van toepassing is op uw serverversie, aangezien aangepaste GUC's zijn gewijzigd in 9.2 . -
Pas uw applicatie zo aan dat deze databaserollen heeft voor elke applicatiegebruiker.
SET ROLE
aan die gebruiker voordat u aan het werk gaat. Hiermee kunt u niet alleen de ingebouwdecurrent_user
variabele-achtige functie voorSELECT current_user;
, kunt u ook beveiliging in de database afdwingen . Zie deze vraag. U kunt direct inloggen als gebruiker in plaats vanSET ROLE
. te gebruiken , maar dat maakt het poolen van verbindingen vaak moeilijk.
In alle drie de gevallen ben je aan het poolen, je moet voorzichtig zijn om DISCARD ALL;
wanneer u weer verbinding maakt met het zwembad. (Hoewel dit niet is gedocumenteerd, DISCARD ALL
doet een RESET ROLE
).
Algemene instellingen voor demo's:
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();
Een GUC gebruiken:
- In de
CUSTOMIZED OPTIONS
sectie vanpostgresql.conf
, voeg een regel toe zoalsmyapp.username = 'unknown_user'
. Op PostgreSQL-versies ouder dan 9.2 moet u ookcustom_variable_classes = 'myapp'
instellen . - Start PostgreSQL opnieuw. U kunt nu
SHOW myapp.username
en krijg de waardeunknown_user
.
Nu kunt u SET myapp.username = 'the_user';
. gebruiken wanneer u een verbinding tot stand brengt, of afwisselend SET LOCAL myapp.username = 'the_user';
na BEGIN
een transactie uitvoeren als u wilt dat deze transactie-lokaal is, wat handig is voor gepoolde verbindingen.
De get_app_user
functiedefinitie:
CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
SELECT current_setting('myapp.username');
$$ LANGUAGE sql;
Demo met SET LOCAL
voor transactie-lokale huidige gebruikersnaam:
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)
Als u SET
. gebruikt in plaats van SET LOCAL
de instelling wordt niet teruggedraaid tijdens de commit/rollback-tijd, dus het is persistent gedurende de hele sessie. Het wordt nog steeds gereset door 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)
Houd er ook rekening mee dat u SET
. niet kunt gebruiken of SET LOCAL
met bindingsparameters aan de serverzijde. Als u bindparameters ("voorbereide instructies") wilt gebruiken, kunt u overwegen het functieformulier set_config(...)
te gebruiken . Zie systeembeheerfuncties
Een tijdelijke tabel gebruiken
Deze benadering vereist het gebruik van een trigger (of hulpfunctie die bij voorkeur wordt aangeroepen door een trigger) die probeert een waarde te lezen uit een tijdelijke tabel die elke sessie zou moeten hebben. Als de tijdelijke tabel niet kan worden gevonden, wordt een standaardwaarde opgegeven. Dit is waarschijnlijk enigszins traag . Test zorgvuldig.
De get_app_user()
definitie:
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
Veilige sessievariabelen
Er is ook een voorstel om "veilige sessievariabelen" toe te voegen aan PostgreSQL. Dit zijn een beetje zoals pakketvariabelen. Vanaf PostgreSQL 12 is de functie niet inbegrepen, maar houd de lijst met hackers in de gaten als dit iets is dat u nodig heeft.
Geavanceerd:uw eigen extensie met gedeelde geheugenruimte
Voor geavanceerd gebruik kunt u zelfs uw eigen C-extensie een gedeeld geheugengebied laten registreren en communiceren tussen backends met behulp van C-functieaanroepen die waarden in een DSA-segment lezen/schrijven. Zie de PostgreSQL-programmeervoorbeelden voor details. Je hebt kennis, tijd en geduld van C nodig.