Strategi yang digunakan mengasumsikan penggunaan konsep "Logika bisnis dalam database", yang dijelaskan lebih detail di sini - Esai tentang implementasi logika bisnis pada level fungsi tersimpan PostgreSQL. Bagian
teoretis dijelaskan dengan sempurna dalam dokumentasi Postgres Pro - Kebijakan keamanan baris . Di bawah ini kami mempertimbangkan implementasi praktis dari tugas bisnis tertentu - model akses data berbasis peran.
Artikel bukanlah hal baru, tidak ada makna tersembunyi dan pengetahuan rahasia. Sekadar sketsa tentang implementasi praktis dari ide teoritis. Jika ada yang tertarik, baca terus. Siapa yang tidak tertarik - jangan buang waktu Anda.
Rumusan masalah
Perlu membatasi akses untuk melihat / menyisipkan / memodifikasi / menghapus dokumen sesuai dengan peran pengguna aplikasi. Peran berarti entri dalam tabel peran yang terkait dalam hubungan banyak ke banyak dengan tabel pengguna . Rincian implementasi tabel dihilangkan karena hal sepele. Selain itu, detail implementasi khusus yang terkait dengan domain dihilangkan.
Penerapan
Kami membuat peran, skema, tabel
Membuat objek database
CREATE ROLE store;
CREATE SCHEMA store AUTHORIZATION store;
CREATE TABLE store.docs
(
id integer , --id
man_id integer , --id
stat_id integer , --id
...
is_del BOOLEAN DEFAULT FALSE
);
ALTER TABLE store.docs ADD CONSTRAINT doc_pk PRIMARY KEY (id);
ALTER TABLE store.docs OWNER TO store ;
Membuat fungsi untuk mengimplementasikan RLS
Memeriksa apakah suatu baris adalah SELECT
check_select
CREATE OR REPLACE FUNCTION store.check_select ( current_id store.docs.id%TYPE ) RETURNS boolean AS $$
DECLARE
result boolean ;
curr_pid integer ;
curr_stat_id integer ;
doc_man_id integer ;
BEGIN
-- DBA
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
-- '' -
SELECT
is_del
INTO
result
FROM
store.docs
WHERE
id = current_id ;
IF result = TRUE
THEN
RETURN FALSE ;
END IF ;
--------------------------------
-- id
SELECT
service_function.get_curr_pid ()
INTO
curr_pid ;
--------------------------------
-- id
SELECT
man_id
INTO
doc_man_id
FROM
store.docs
WHERE
id = current_id ;
--------------------------------
--
--
IF doc_man_id != curr_pid OR doc_man_id IS NULL
THEN
RETURN TRUE ;
ELSE
--
SELECT
stat_id
INTO
curr_statid
FROM
store.docs
WHERE
id = current_id ;
-- -
IF curr_statid = 4 OR curr_statid = 9
THEN
RETURN TRUE ;
ELSE
-- -
RETURN FALSE ;
END IF ;
END IF ;
--------------------------------
RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.check_select( store.docs.id%TYPE ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.check_select( store.docs.id%TYPE ) FROM public;
GRANT EXECUTE ON FUNCTION store.check_select( store.docs.id%TYPE ) TO service_functions;
Memeriksa INSERT Rows
check_insert
CREATE OR REPLACE FUNCTION store.check_insert ( current_id store.docs.id%TYPE ) RETURNS boolean AS $$
DECLARE
curr_role_id integer ;
BEGIN
--DBA
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
-- id
SELECT
service_functions.current_rid()
INTO
curr_role_id ;
--------------------------------
--
--
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 ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.check_insert( store.docs.id%TYPE ) FROM public;
GRANT EXECUTE ON FUNCTION store.check_insert( store.docs.id%TYPE ) TO service_functions;
Memeriksa apakah baris bisa DIHAPUS
check_delete
CREATE OR REPLACE FUNCTION store.check_delete ( current_id store.docs.id%TYPE )
RETURNS boolean AS $$
BEGIN
-- DBA
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 ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.check_delete( store.docs.id%TYPE ) FROM public;Memeriksa apakah baris tersebut dapat DIPERBARUI.
update_using
CREATE OR REPLACE FUNCTION store.update_using ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean AS $$
BEGIN
-- '' -
IF is_del
THEN
RETURN FALSE ;
ELSE
RETURN TRUE ;
END IF ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.update_using( store.docs.id%TYPE , boolean ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.update_using( store.docs.id%TYPE , boolean ) FROM public;
GRANT EXECUTE ON FUNCTION store.update_using( store.docs.id%TYPE ) TO service_functions;
update_check
CREATE OR REPLACE FUNCTION store.update_with_check ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean AS $$
DECLARE
current_rid integer ;
current_statid integer ;
BEGIN
--DBA
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
-- id
SELECT
service_functions.current_rid()
INTO
curr_role_id ;
--------------------------------
-- -
IF is_deleted
THEN
-- ***
IF current_role_id = 3
THEN
SELECT
stat_id
INTO
curr_statid
FROM
store.docs
WHERE
id = current_id ;
-- ***
IF current_status_id = 11
THEN
RETURN FALSE ;
ELSE
--
RETURN TRUE ;
END IF ;
-- , ***
ELSIF current_role_id = 5
THEN
--
RETURN TRUE ;
ELSE
--
RETURN FALSE ;
END IF ;
ELSE
--
RETURN TRUE ;
END IF ;
RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.update_with_check( storg.docs.id%TYPE , boolean ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.update_with_check( storg.docs.id%TYPE , boolean ) FROM public;
GRANT EXECUTE ON FUNCTION store.update_with_check( store.docs.id%TYPE ) TO service_functions;Mengaktifkan kebijakan Keamanan Tingkat Baris untuk tabel.
AKTIFKAN KEAMANAN ROW LEVEL
ALTER TABLE store.docs ENABLE ROW LEVEL SECURITY ;
CREATE POLICY doc_select ON store.docs FOR SELECT TO service_functions USING ( (SELECT store.check_select(id)) );
CREATE POLICY doc_insert ON store.docs FOR INSERT TO service_functions WITH CHECK ( (SELECT store.check_insert(id)) );
CREATE POLICY docs_delete ON store.docs FOR DELETE TO service_functions USING ( (SELECT store.check_delete(id)) );
CREATE POLICY doc_update_using ON store.docs FOR UPDATE TO service_functions USING ( (SELECT store.update_using(id , is_del )) );
CREATE POLICY doc_update_check ON store.docs FOR UPDATE TO service_functions WITH CHECK ( (SELECT store.update_with_check(id , is_del )) );Hasil
Berhasil.
Strategi yang diusulkan memungkinkan kami untuk memindahkan implementasi model peran dari tingkat fungsi bisnis ke tingkat penyimpanan data.
Fungsi dapat digunakan sebagai template untuk mengimplementasikan model penyembunyian data yang lebih canggih jika persyaratan bisnis memerlukannya.