Frage

Ich habe ein Schema von Tabellen, deren Inhalt im Grunde laufen auf:

  • Eine Gruppe von Benutzern
  • Ein Satz von Objektgruppen
  • Eine Zugriffssteuerungsliste (ACL), das angibt, welche Benutzer Zugriff auf welche Gruppen
  • Eine Gruppe von Objekten, von denen jeder gehört zu genau einer Gruppe.

Ich möchte eine einfache Anwendung erstellen, unterstützt die Steuerung zugreifen. Ich denke Ansichten hier einen guten Ansatz wären.

Angenommen, ich habe folgende Datenbankinitialisierung:

/* 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;

Meine Idee ist Ansichten zu verwenden, der die Datenbank spiegeln, sondern beschränken Inhalt nur, dass die der aktuelle Benutzer (von meinem PHP-Skript ermittelt) zugreifen kann (hier werde ich nur den Benutzer ‚bob‘ verwenden). Angenommen, ich betreibe diese am Anfang jeder PostgreSQL-Sitzung (dh jedes Mal, wenn jemand eine Seite auf meiner Website zugreift):

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;

Meine Frage ist, ist dies ein guter Ansatz? Haben diese CREATE TEMPORARY VIEW-Anweisungen erzeugen erheblichen Aufwand, vor allem im Vergleich zu ein paar einfache Abfragen?

Auch ist es eine Möglichkeit, diese Ansichten permanent in meiner Datenbank Definition zu machen, dann binden einen Wert für den Benutzernamen pro Sitzung? Auf diese Weise ist es nicht jedes Mal all diese Ansichten erstellen hat einen Benutzer lädt eine Seite.

War es hilfreich?

Lösung

Mehrere Probleme mit diesem Ansatz:

  1. Ein Benutzer web Sitzung ist nicht das gleiche wie eine Datenbank Sitzung. Mehrere Benutzer mit mit Art-Setup würden sofort fehlschlagen.

  2. Management-Overhead zu schaffen / die Ansichten zu zerstören.

Stattdessen würde ich so etwas wie die folgende Ansicht empfehlen:

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_

Dann überall Sie Objekte auswählen:

SELECT * FROM AllowedObjects
WHERE alloweduser='Bob'

Dies setzt voraus, Bob kann nur eine ACL hat ihn zu einer bestimmten Gruppe anzuschließen, da sonst ein DISTINCT notwendig wäre.

Dies zu einer leicht abstrahiert werden könnte weniger komplex Ansicht, die verwendet werden könnte, um es einfache Berechtigungen für UPDATE und DELETE zu überprüfen:

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_

Dies stellt eine abgeflachte Ansicht, welche Benutzer in welchen Gruppen sind, die Sie überprüfen können, gegen die Tabellenobjekten während einer UPDATE / DELETE:

UPDATE objects SET foo='bar' WHERE id=42 AND EXISTS
(SELECT NULL FROM AllowedUserGroup 
 WHERE alloweduser='Bob' AND allowedgroup = objects.group_)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top