我有一个表的模式,其内容基本上可以归结为:
-
一组用户
-
一组对象组
-
访问控制列表(ACL),指示哪些用户可以访问哪些组
-
一组对象,每个对象恰好属于一个组。
我想创建一个支持访问控制的简单应用程序。我认为观点是一个很好的方法。
假设我进行了以下数据库初始化:
/* 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;
我的想法是使用镜像数据库的视图,但仅限于当前用户(由我的PHP脚本确定)可以访问的内容(这里我只使用用户“bob”)。假设我在每一个PostgreSQL会话的开头运行这个(意味着每次有人访问我的站点上的页面时):
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;
我的问题是,这是一个好方法吗?这些创建临时视图语句是否会产生很大的开销,特别是与几个简单查询相比?
另外,是否有一种方法可以使这些视图在我的数据库定义中保持永久性,然后在每个会话中将一个值绑定到用户名?这样,就不必每次用户加载页面时都创建所有这些视图。