Alternativen inkluderar:
-
När du öppnar en anslutning,
CREATE TEMPORARY TABLE current_app_user(username text); INSERT INTO current_app_user(username) VALUES ('the_user');
. Sedan i din trigger,SELECT username FROM current_app_user
för att få det aktuella användarnamnet, eventuellt som en underfråga. -
I
postgresql.conf
skapa en post för en anpassad GUC sommy_app.username = 'unknown';
. När du skapar en anslutning körSET my_app.username = 'the_user';
. Sedan i triggers, användcurrent_setting('my_app.username')
funktion för att få värdet. I själva verket missbrukar du GUC-maskineriet för att tillhandahålla sessionsvariabler. Läs dokumentationen som är lämplig för din serverversion, eftersom anpassade GUC:er ändrades i 9.2 . -
Justera din applikation så att den har databasroller för varje applikationsanvändare.
SET ROLE
till den användaren innan arbetet utförs. Detta låter dig inte bara använda den inbyggdacurrent_user
variabelliknande funktion tillSELECT current_user;
, det låter dig också upprätthålla säkerhet i databasen . Se den här frågan. Du kan logga in direkt som användare istället för att användaSET ROLE
, men det tenderar att göra anslutningspooling svår.
I båda alla tre fallen du anslutningspooler måste du vara noga med att DISCARD ALL;
när du återställer en anslutning till poolen. (Även om det inte är dokumenterat att det gör det, DISCARD ALL
gör en RESET ROLE
).
Gemensamma inställningar 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();
Använda en GUC:
- I
CUSTOMIZED OPTIONS
avsnitt avpostgresql.conf
, lägg till en rad sommyapp.username = 'unknown_user'
. På PostgreSQL-versioner äldre än 9.2 måste du också ställa incustom_variable_classes = 'myapp'
. - Starta om PostgreSQL. Du kommer nu att kunna
SHOW myapp.username
och hämta värdetunknown_user
.
Nu kan du använda SET myapp.username = 'the_user';
när du upprättar en anslutning, eller alternativt SET LOCAL myapp.username = 'the_user';
efter BEGIN
ning en transaktion om du vill att den ska vara transaktionslokal, vilket är bekvämt för poolade anslutningar.
get_app_user
funktionsdefinition:
CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
SELECT current_setting('myapp.username');
$$ LANGUAGE sql;
Demo med SET LOCAL
för transaktionslokalt aktuellt användarnamn:
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)
Om du använder SET
istället för SET LOCAL
inställningen kommer inte att återställas vid commit/back-tid, så den är beständig under hela sessionen. Den är fortfarande återställd av 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)
Observera också att du inte kan använda SET
eller SET LOCAL
med bindningsparametrar på serversidan. Om du vill använda bindningsparametrar ("prepared statements"), överväg att använda funktionsformuläret set_config(...)
. Se systemadministrationsfunktioner
Använda en tillfällig tabell
Detta tillvägagångssätt kräver användning av en trigger (eller hjälpfunktion som helst anropas av en trigger) som försöker läsa ett värde från en temporär tabell som varje session ska ha. Om den temporära tabellen inte kan hittas, tillhandahålls ett standardvärde. Det här kommer sannolikt att gå något långsamt . Testa noggrant.
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
Säker sessionsvariabler
Det finns också ett förslag om att lägga till "säkra sessionsvariabler" till PostgreSQL. Dessa är lite som paketvariabler. Från och med PostgreSQL 12 har funktionen inte inkluderats, men håll utkik och säg till på hackerlistan om detta är något du behöver.
Avancerat:ditt eget tillägg med delat minnesområde
För avancerad användning kan du till och med ha ditt eget C-tillägg registrera ett delat minnesområde och kommunicera mellan backends med C-funktionsanrop som läser/skriver värden i ett DSA-segment. Se PostgreSQL-programmeringsexemplen för detaljer. Du behöver C-kunskap, tid och tålamod.