sql >> Database teknologi >  >> RDS >> PostgreSQL

Sender bruger-id til PostgreSQL-udløsere

Indstillinger omfatter:

  • Når du åbner en forbindelse, CREATE TEMPORARY TABLE current_app_user(username text); INSERT INTO current_app_user(username) VALUES ('the_user'); . I din trigger, SELECT username FROM current_app_user for at få det aktuelle brugernavn, eventuelt som en underforespørgsel.

  • I postgresql.conf opret en post for en tilpasset GUC som my_app.username = 'unknown'; . Hver gang du opretter en forbindelse, kør SET my_app.username = 'the_user'; . I triggere skal du derefter bruge current_setting('my_app.username') funktion for at opnå værdien. Faktisk misbruger du GUC-maskineriet til at levere sessionsvariabler. Læs dokumentationen, der passer til din serverversion, da tilpassede GUC'er blev ændret i 9.2 .

  • Juster din applikation, så den har databaseroller for hver applikationsbruger. SET ROLE til den pågældende bruger, før arbejdet udføres. Dette lader dig ikke kun bruge den indbyggede current_user variabel-lignende funktion til SELECT current_user; , det giver dig også mulighed for at håndhæve sikkerheden i databasen . Se dette spørgsmål. Du kan logge ind direkte som bruger i stedet for at bruge SET ROLE , men det har en tendens til at gøre forbindelsespooling svær.

I begge alle tre tilfælde, hvor du samler forbindelse, skal du være omhyggelig med at DISCARD ALL; når du returnerer en forbindelse til poolen. (Selvom det ikke er dokumenteret at gøre det, DISCARD ALL udfører en RESET ROLE ).

Fælles opsætning for demoer:

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();

Brug af en GUC:

  • I CUSTOMIZED OPTIONS sektion af postgresql.conf , tilføj en linje som myapp.username = 'unknown_user' . På PostgreSQL-versioner ældre end 9.2 skal du også indstille custom_variable_classes = 'myapp' .
  • Genstart PostgreSQL. Du vil nu være i stand til at SHOW myapp.username og få værdien unknown_user .

Nu kan du bruge SET myapp.username = 'the_user'; når du etablerer en forbindelse, eller alternativt SET LOCAL myapp.username = 'the_user'; efter BEGIN ning af en transaktion, hvis du ønsker, at den skal være transaktionslokal, hvilket er praktisk for poolede forbindelser.

get_app_user funktionsdefinition:

CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
    SELECT current_setting('myapp.username');
$$ LANGUAGE sql;

Demo ved hjælp af SET LOCAL for transaktionslokalt nuværende brugernavn:

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)

Hvis du bruger SET i stedet for SET LOCAL indstillingen bliver ikke vendt tilbage ved commit/rollback-tidspunkt, så den er vedvarende i hele sessionen. Det er stadig nulstillet af 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)

Bemærk også, at du ikke kan bruge SET eller SET LOCAL med bindingsparametre på serversiden. Hvis du vil bruge bindeparametre ("forberedte sætninger"), kan du overveje at bruge funktionsformen set_config(...) . Se systemadministrationsfunktioner

Brug af en midlertidig tabel

Denne tilgang kræver brug af en trigger (eller hjælperfunktion kaldet af en trigger, helst), der forsøger at læse en værdi fra en midlertidig tabel, hver session skal have. Hvis den midlertidige tabel ikke kan findes, leveres en standardværdi. Dette vil sandsynligvis være lidt langsomt . Test omhyggeligt.

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

Sikrede sessionsvariabler

Der er også et forslag om at tilføje "sikre sessionsvariabler" til PostgreSQL. Disse er lidt ligesom pakkevariabler. Fra og med PostgreSQL 12 er funktionen ikke inkluderet, men hold øje og fortæl hackerlisten, hvis det er noget du har brug for.

Avanceret:din egen udvidelse med delt hukommelsesområde

Til avanceret brug kan du endda få din egen C-udvidelse til at registrere et delt hukommelsesområde og kommunikere mellem backends ved hjælp af C-funktionskald, der læser/skriver værdier i et DSA-segment. Se PostgreSQL-programmeringseksemplerne for detaljer. Du skal bruge C viden, tid og tålmodighed.



  1. Hvordan tilføjes slettekaskadebegrænsninger?

  2. Kan ikke indlæse SqlServerSpatial.dll

  3. 13 blogartikler om bedste praksis og tips til databasedesign

  4. Lower()-funktionen på internationale tegn i postgresql