Pregunta

Tengo un esquema de tablas cuyos contenidos básicamente se reducen a:

  • un conjunto de usuarios
  • un conjunto de grupos de objetos
  • Una lista de control de acceso (ACL) que indica lo que los usuarios tienen acceso a qué grupos
  • un conjunto de objetos, cada uno de los cuales pertenece a exactamente un grupo.

Quiero crear una sencilla aplicación que admita el acceso de control. Estoy pensando vistas serían un enfoque bien aquí.

Supongamos que tengo la siguiente inicialización de la base de datos:

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

Mi idea es utilizar puntos de vista que reflejan la base de datos, pero restringir el contenido a sólo lo que el usuario actual (comprobado por mi script PHP) puede acceder (aquí sólo voy a utilizar el 'bob' usuario). Supongamos que yo corro esto al comienzo de cada sesión de PostgreSQL (es decir, cada vez que alguien accede a una página en mi sitio):

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;

Mi pregunta es, ¿es una buena aproximación? Hacer estas CREATE VIEW TEMPORAL producen una sobrecarga significativa, especialmente en comparación con un par de simples consultas?

Además, ¿hay una manera de hacer que estos puntos de vista permanente en mi definición de base de datos, a continuación, se unen un valor al nombre de usuario por sesión? De esta manera, no tiene que crear todos estos puntos de vista cada vez que un usuario carga una página.

¿Fue útil?

Solución

Varios problemas con este enfoque:

  1. Uno de usuario web sesión no es lo mismo que un base de datos sesión. Varios usuarios con la clase de disposición fallarían al instante.

  2. Administración de sobrecarga de la creación / destrucción de las vistas.

En su lugar, yo recomendaría algo así como los próximos:

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_

A continuación, en todas partes se seleccionan objetos:

SELECT * FROM AllowedObjects
WHERE alloweduser='Bob'

Esto supone Bob sólo puede tener un ACL unirse a él a un grupo en particular, de lo contrario un DISTINCT sería necesario.

Esto podría ser abstraído a una vista ligeramente menos compleja que podría ser utilizado para hacer más fácil para comprobar permisos para actualizar y eliminar:

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_

Esto proporciona una vista aplanada de las cuales los usuarios están en la que los grupos, que se puede comprobar en contra de los objetos mesa durante un UPDATE / DELETE:

UPDATE objects SET foo='bar' WHERE id=42 AND EXISTS
(SELECT NULL FROM AllowedUserGroup 
 WHERE alloweduser='Bob' AND allowedgroup = objects.group_)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top