Question

J'ai un schéma de tables dont le contenu se résument essentiellement à:

  • Un ensemble d'utilisateurs
  • un ensemble de groupes d'objets
  • Une liste de contrôle d'accès (ACL) indiquant ce que les utilisateurs ont accès à quels groupes
  • Un ensemble d'objets, chacun d'eux appartient à un seul groupe.

Je veux créer une application simple qui prend en charge le contrôle d'accès. Je pense vue serait une bonne approche ici.

Supposons que je l'initialisation de la base de données suivante:

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

Mon idée est d'utiliser des vues qui reflètent la base de données, mais limiter le contenu à seulement ce que l'utilisateur actuel (vérifié par mon script PHP) peut accéder (ici, je vais utiliser l'utilisateur « bob »). Supposons que je lance ce au début de chaque session PostgreSQL (qui signifie chaque fois que quelqu'un accède à une page sur mon site):

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;

Ma question est, est-ce une bonne approche? Est-ce que ces instructions CREATE VIEW TEMPORAIRES produisent les frais généraux importants, en particulier par rapport à un couple des requêtes simples?

Aussi, est-il un moyen de rendre ces points de vue permanente dans ma définition de base de données, puis lier une valeur au nom d'utilisateur par session? De cette façon, il ne dispose pas de créer toutes ces vues chaque fois qu'un utilisateur charge une page.

Était-ce utile?

La solution

Plusieurs problèmes avec cette approche:

  1. Un utilisateur web session n'est pas la même chose que l'un base de données session. Plusieurs utilisateurs avec de configuration avec sorte échoueraient instantanément.

  2. frais généraux de gestion création / destruction des vues.

Au lieu de cela, je recommanderais quelque chose comme la vue suivante:

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_

Alors, partout où vous sélectionnez des objets:

SELECT * FROM AllowedObjects
WHERE alloweduser='Bob'

Cela suppose Bob ne peut avoir qu'un ACL se joindre à lui à un groupe particulier, sinon un DISTINCT serait nécessaire.

Cela pourrait être une vue à abstraire un peu moins complexe qui pourrait être utilisé pour faciliter pour vérifier les autorisations pour UPDATE et 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_

Ceci fournit une vue aplaties dont les utilisateurs sont dans quels groupes, que vous pouvez vérifier sur la table des objets lors d'une UPDATE / DELETE:

UPDATE objects SET foo='bar' WHERE id=42 AND EXISTS
(SELECT NULL FROM AllowedUserGroup 
 WHERE alloweduser='Bob' AND allowedgroup = objects.group_)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top