Domanda

Ho uno schema di tabelle il cui contenuto si riduce sostanzialmente a:

  • Un insieme di utenti
  • Un insieme di gruppi di oggetti
  • Un elenco di controllo degli accessi (acl) che indica quali utenti hanno accesso a quali gruppi
  • Un insieme di oggetti, ciascuno dei quali appartiene esattamente a un gruppo.

Voglio creare una semplice applicazione che supporti il ​​controllo degli accessi.Penso che le visualizzazioni sarebbero un buon approccio qui.

Supponiamo di avere la seguente inizializzazione del database:

/* Database definition */

BEGIN;

CREATE SCHEMA foo;

CREATE TABLE foo.users (
    id SERIAL PRIMARY KEY,
    name TEXT
);

CREATE TABLE foo.groups (
    id SERIAL PRIMARY KEY,
    name TEXT
);

CREATE TABLE foo.acl (
    user_ INT REFERENCES foo.users,
    group_ INT REFERENCES foo.groups
);

CREATE TABLE foo.objects (
    id SERIAL PRIMARY KEY,
    group_ INT REFERENCES foo.groups,
    name TEXT,
    data TEXT
);

/* Sample data */

-- Create groups A and B
INSERT INTO foo.groups VALUES (1, 'A');
INSERT INTO foo.groups VALUES (2, 'B');

-- Create objects belonging to group A
INSERT INTO foo.objects VALUES (1, 1, 'object in A', 'apples');
INSERT INTO foo.objects VALUES (2, 1, 'another object in A', 'asparagus');

-- Create objects belonging to group B
INSERT INTO foo.objects VALUES (3, 2, 'object in B', 'bananas');
INSERT INTO foo.objects VALUES (4, 2, 'object in B', 'blueberries');

-- Create users
INSERT INTO foo.users VALUES (1, 'alice');
INSERT INTO foo.users VALUES (2, 'amy');
INSERT INTO foo.users VALUES (3, 'billy');
INSERT INTO foo.users VALUES (4, 'bob');
INSERT INTO foo.users VALUES (5, 'caitlin');
INSERT INTO foo.users VALUES (6, 'charlie');

-- alice and amy can access group A
INSERT INTO foo.acl VALUES (1, 1);
INSERT INTO foo.acl VALUES (2, 1);

-- billy and bob can access group B
INSERT INTO foo.acl VALUES (3, 2);
INSERT INTO foo.acl VALUES (4, 2);

-- caitlin and charlie can access groups A and B
INSERT INTO foo.acl VALUES (5, 1);
INSERT INTO foo.acl VALUES (5, 2);
INSERT INTO foo.acl VALUES (6, 1);
INSERT INTO foo.acl VALUES (6, 2);

COMMIT;

La mia idea è quella di utilizzare viste che rispecchiano il database, ma limitano il contenuto solo a ciò a cui l'utente corrente (accertato dal mio script PHP) può accedere (qui userò semplicemente l'utente "bob").Supponiamo di eseguirlo all'inizio di ogni sessione PostgreSQL (ovvero ogni volta che qualcuno accede a una pagina sul mio sito):

BEGIN;

CREATE TEMPORARY VIEW users AS
SELECT * FROM foo.users
WHERE name='bob';

CREATE TEMPORARY VIEW acl AS
SELECT acl.* FROM foo.acl, users
WHERE acl.user_=users.id;

CREATE TEMPORARY VIEW groups AS
SELECT groups.* FROM foo.groups, acl
WHERE groups.id=acl.group_;

CREATE TEMPORARY VIEW objects AS
SELECT objects.* FROM foo.objects, groups
WHERE objects.group_=groups.id;

COMMIT;

La mia domanda è: è un buon approccio?Queste istruzioni CREATE TEMPORARY VIEW producono un sovraccarico significativo, soprattutto rispetto a un paio di semplici query?

Inoltre, esiste un modo per rendere queste visualizzazioni permanenti nella definizione del mio database, quindi associare un valore al nome utente per sessione?In questo modo, non è necessario creare tutte queste visualizzazioni ogni volta che un utente carica una pagina.

È stato utile?

Soluzione

Diversi problemi con questo approccio:

  1. Un utente ragnatela una sessione non è la stessa cosa di una Banca dati sessione.Più utenti con una sorta di configurazione fallirebbero immediatamente.

  2. Overhead di gestione che crea/distrugge le viste.

Invece, consiglierei qualcosa di simile alla seguente visualizzazione:

CREATE VIEW AllowedObjects
SELECT objects.*, users.name AS alloweduser
FROM objects
   INNER JOIN groups ON groups.id = objects.group_
   INNER JOIN acl ON acl.group_ = groups.id
   INNER JOIN users ON users.id = acl.user_

Quindi, ovunque selezioni gli oggetti:

SELECT * FROM AllowedObjects
WHERE alloweduser='Bob'

Ciò presuppone che Bob possa avere solo un ACL che lo unisce a un particolare gruppo, altrimenti sarebbe necessario un DISTINCT.

Questo potrebbe essere astratto in una vista leggermente meno complessa che potrebbe essere utilizzata per rendere più semplice il controllo delle autorizzazioni per UPDATE e DELETE:

CREATE VIEW AllowedUserGroup
SELECT groups.id AS allowedgroup, users.name AS alloweduser
FROM groups
   INNER JOIN acl ON acl.group_ = groups.id
   INNER JOIN users ON users.id = acl.user_

Ciò fornisce una vista appiattita di quali utenti si trovano in quali gruppi, che puoi verificare rispetto alla tabella degli oggetti durante un AGGIORNAMENTO/ELIMINA:

UPDATE objects SET foo='bar' WHERE id=42 AND EXISTS
(SELECT NULL FROM AllowedUserGroup 
 WHERE alloweduser='Bob' AND allowedgroup = objects.group_)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top