Utvikling av tema og for et utfyllende svar En funksjon har blitt
Den brukte strategien innebĂŠrer konseptet «Forretningslogikk i DB», som ble beskrevet litt mer detaljert her â
Teoretisk del er godt beskrevet i dokumentasjonen â . Nedenfor er den praktiske implementeringen vurdert av en bestemt forretningsoppgave â en rollemodell for datatilgang.

Artikkelen inneholder ingenting nytt, ingen skjulte betydninger eller hemmelig kunnskap. Bare en skisse over den praktiske implementeringen av en teoretisk idĂ©. Hvis noen er interessert â les. Hvis ikke â ikke kast bort tiden din.
Definering av oppgaven
Det er nÞdvendig Ä skille mellom tilgang til visning/insetting/endring/sletting av dokumentet i henhold til brukerens rolle i applikasjonen. Med rolle menes en post i tabellen roles relatert til mange-til-mange-forhold med tabellen users. Detaljer om implementeringen av tabellene er utelatt pÄ grunn av trivielle grunner. Spesifikke detaljer knyttet til fagomrÄdet er ogsÄ utelatt.
Implementering
Vi oppretter roller, skjema, tabellen
Oppretting av DB-objekter
CREATE ROLE store;
CREATE SCHEMA store AUTHORIZATION store;
CREATE TABLE store.docs
(
id integer , --id for dokumentet
man_id integer , --id for dokumentets manager
stat_id integer , --id for dokumentets status
...
is_del BOOLEAN DEFAULT FALSE
);
ALTER TABLE store.docs ADD CONSTRAINT doc_pk PRIMARY KEY (id);
ALTER TABLE store.docs OWNER TO store ;
Vi lager funksjoner for implementering av RLS
Sjekk muligheten til Ä utfÞre SELECT pÄ raden
check_select
OPPRETT FUNKSJON store.check_select ( current_id store.docs.id%TYPE ) RETURNER boolean AS $$
DECLARE
result boolean ;
curr_pid integer ;
curr_stat_id integer ;
doc_man_id integer ;
BEGIN
-- DBA har tilgang til alle dokumenter
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
--Hvis dokumentet har merkelapp 'slettet' - ikke vis i utvalget
SELECT
is_del
INTO
result
FROM
store.docs
WHERE
id = current_id ;
IF result = TRUE
THEN
RETURN FALSE ;
END IF ;
--------------------------------
--FĂ„ id til aktuell bruker
SELECT
service_function.get_curr_pid ()
INTO
curr_pid ;
--------------------------------
--FĂ„ id til dokumentets manager
SELECT
man_id
INTO
doc_man_id
FROM
store.docs
WHERE
id = current_id ;
--------------------------------
--Hvis dokumentets manager ikke er aktuell bruker eller manager ikke er utnevnt
--legge dokumentet til i utvalget
IF doc_man_id != curr_pid OR doc_man_id IS NULL
THEN
RETURN TRUE ;
ELSE
--FÄ nÄvÊrende status for dokumentet
SELECT
stat_id
INTO
curr_statid
FROM
store.docs
WHERE
id = current_id ;
--Hvis status tillater visning av dokumentet - legg til dokumentet i utvalget
IF curr_statid = 4 OR curr_statid = 9
THEN
RETURN TRUE ;
ELSE
--Ellers - ekskluder dokumentet fra utvalget
RETURN FALSE ;
END IF ;
END IF ;
--------------------------------
RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.check_select( store.docs.id%TYPE ) EIER TIL store ;
REVOKE EXECUTE ON FUNCTION store.check_select( store.docs.id%TYPE ) FRA public;
GRANT EXECUTE ON FUNCTION store.check_select( store.docs.id%TYPE ) TIL service_functions;
Sjekk muligheten for Ă„ utfĂžre INSERT av rad
check_insert
OPPRETT FUNKSJON store.check_insert ( current_id store.docs.id%TYPE ) RETURNER boolean AS $$
DECLARE
curr_role_id integer ;
BEGIN
--DBA kan alltid legge til en rad
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
--FĂ„ id til rollen til aktuell bruker
SELECT
service_functions.current_rid()
INTO
curr_role_id ;
--------------------------------
--Hvis rollen tillater opprettelse av nytt dokument
--tillat
IF curr_role_id = 3 OR curr_role_id = 5
THEN
RETURN TRUE ;
END IF ;
--------------------------------
RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.check_insert( store.docs.id%TYPE ) EIER TIL store ;
REVOKE EXECUTE ON FUNCTION store.check_insert( store.docs.id%TYPE ) FRA public;
GRANT EXECUTE ON FUNCTION store.check_insert( store.docs.id%TYPE ) TIL service_functions;
Sjekk muligheten for Ă„ utfĂžre DELETE av rad
check_delete
OPPRETT FUNKSJON store.check_delete ( current_id store.docs.id%TYPE )
RETURNER boolean AS $$
BEGIN
--Bare DBA kan slette en rad
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
RETURN FALSE ;
END
$$ LANGUAGE plpgsql
SECURITY DEFINER;
ALTER FUNCTION store.check_delete( store.docs.id%TYPE ) EIER TIL store ;
REVOKE EXECUTE ON FUNCTION store.check_delete( store.docs.id%TYPE ) FRA public;Sjekk muligheten for Ă„ utfĂžre UPDATE av rad.
oppdatere_bruk
OPPRETT ELLER BYTT UT FUNKSJON store.oppdatere_bruk ( nÄvÊrende_id store.docs.id%TYPE , er_del boolean )
RETURNER boolean AS $$
BEGIN
--Dokumenter med status 'slettet' kan ikke redigeres
HVIS er_del
DA
RETURNER FALSE ;
ELLERS
RETURNER TRUE ;
SLUTT HVIS ;
SLUTT
$$ SPRĂ
K plpgsql SIKKERHET DEFINERER;
ENDRE FUNKSJON store.oppdatere_bruk( store.docs.id%TYPE , boolean ) EIER TIL store ;
FJERN UTFĂRELSE PĂ
FUNKSJON store.oppdatere_bruk( store.docs.id%TYPE , boolean ) FRA offentlig;
GI UTFĂRELSE PĂ
FUNKSJON store.oppdatere_bruk( store.docs.id%TYPE ) TIL service_functions;oppdatere_sjekk
OPPRETT ELLER BYTT UT FUNKSJON store.oppdatere_med_sjekk ( nÄvÊrende_id store.docs.id%TYPE , er_del boolean )
RETURNER boolean AS $$
DECLARE
nÄvÊrende_rid integer ;
nÄvÊrende_statid integer ;
BEGIN
--DBA kan se raden
HVIS SESJON_BRUKER = 'curr_dba'
DA
RETURNER TRUE ;
SLUTT HVIS ;
--------------------------------
--Hent id for rollen til den nÄvÊrende brukeren
SELECT
service_functions.nÄvÊrende_rid()
INN I
curr_role_id ;
--------------------------------
--Sletting av dokument - endring av flagg
HVIS er_slettet
DA
--Hvis brukerens rolle ***
HVIS nÄvÊrende_rolle_id = 3
DA
SELECT
stat_id
INN I
curr_statid
FRA
store.docs
HVOR
id = nÄvÊrende_id ;
--Dokumentet med status *** kan ikke slettes
HVIS nÄvÊrende_status_id = 11
DA
RETURNER FALSE ;
ELLERS
--Kan slette dokumentet i andre statuser
RETURNER TRUE ;
SLUTT HVIS ;
--Ellers, hvis brukerens rolle ***
ELLER HVIS nÄvÊrende_rolle_id = 5
DA
--Alle statusene til dokumentet
RETURNER TRUE ;
ELLER
--Andre brukere kan ikke slette dokumenter
RETURNER FALSE ;
SLUTT HVIS ;
ELLERS
--Oppdatering av dokumentet er tillatt
RETURNER TRUE ;
SLUTT HVIS ;
RETURNER FALSE ;
SLUTT
$$ SPRĂ
K plpgsql SIKKERHET DEFINERER;
ENDRE FUNKSJON store.oppdatere_med_sjekk( storg.docs.id%TYPE , boolean ) EIER TIL store ;
FJERN UTFĂRELSE PĂ
FUNKSJON store.oppdatere_med_sjekk( storg.docs.id%TYPE , boolean ) FRA offentlig;
GI UTFĂRELSE PĂ
FUNKSJON store.oppdatere_med_sjekk( store.docs.id%TYPE ) TIL service_functions;Aktivering av Row Level Security-policy for tabellen.
AKTIVER ROW LEVEL SECURITY
ENDRE TABELL store.docs AKTIVER ROW LEVEL SECURITY ;
OPPRETT POLICY doc_select PĂ
store.docs FOR SELEKTERING TIL service_functions BRUKER ( (SELECT store.check_select(id)) );
OPPRETT POLICY doc_insert PĂ
store.docs FOR SETTING TIL service_functions MED SJEKK ( (SELECT store.check_insert(id)) );
OPPRETT POLICY docs_delete PĂ
store.docs FOR SLETTING TIL service_functions BRUKER ( (SELECT store.check_delete(id)) );
OPPRETT POLICY doc_update_using PĂ
store.docs FOR OPPDATERING TIL service_functions BRUKER ( (SELECT store.oppdatere_bruk(id , er_del )) );
OPPRETT POLICY doc_update_check PĂ
store.docs FOR OPPDATERING TIL service_functions MED SJEKK ( (SELECT store.oppdatere_med_sjekk(id , er_del )) );Resultat
Det fungerer.
Den foreslÄtte strategien gjorde det mulig Ä flytte implementeringen av rollemodellen fra nivÄet for forretningsfunksjoner til nivÄet for datalagring.
Funksjoner kan brukes som en mal for implementering av mer sofistikerte modeller for dataskjuling, hvis forretningskravene tilsier det.
Kilde: habr.com
