5

基本的に内容が次のように要約されるテーブルのスキーマがあります。

  • ユーザーのセット
  • オブジェクト グループのセット
  • どのユーザーがどのグループにアクセスできるかを示すアクセス制御リスト (acl)
  • それぞれが 1 つのグループに属するオブジェクトのセット。

アクセス制御をサポートする簡単なアプリケーションを作成したいと考えています。ここではビューが良いアプローチになると思います。

次のデータベースの初期化があるとします。

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

私の質問は、これは良いアプローチですか?これらの CREATE TEMPORARY VIEW ステートメントは、特にいくつかの単純なクエリと比較して、大きなオーバーヘッドを生み出しますか?

また、データベース定義でこれらのビューを永続化し、セッションごとに値をユーザー名にバインドする方法はありますか? このように、ユーザーがページをロードするたびにこれらすべてのビューを作成する必要はありません。

4

1 に答える 1

7

このアプローチに関するいくつかの問題:

  1. 1つのユーザーWebセッションは、1つのデータベースセッションと同じものではありません。ある種の設定をしている複数のユーザーはすぐに失敗します。

  2. ビューを作成/破棄する管理オーバーヘッド。

代わりに、次のビューのようなものをお勧めします。

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_

次に、オブジェクトを選択するすべての場所で:

SELECT * FROM AllowedObjects
WHERE alloweduser='Bob'

これは、ボブが特定のグループに参加できるACLを1つだけ持つことができることを前提としています。そうでない場合は、DISTINCTが必要になります。

これは、少し複雑でないビューに抽象化できます。これを使用すると、UPDATEおよび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_

これにより、どのユーザーがどのグループに属しているかがフラット化されたビューが提供され、UPDATE/DELETE中にオブジェクトテーブルと照合できます。

UPDATE objects SET foo='bar' WHERE id=42 AND EXISTS
(SELECT NULL FROM AllowedUserGroup 
 WHERE alloweduser='Bob' AND allowedgroup = objects.group_)
于 2010-02-22T06:39:19.383 に答える