سؤال

لديّ مخطط من الجداول التي تتجول محتوياتها بشكل أساسي إلى:

  • مجموعة من المستخدمين
  • مجموعة من مجموعات الكائنات
  • قائمة التحكم في الوصول (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;

سؤالي هو ، هل هذا نهج جيد؟ هل تؤدي هذه البيانات إلى أن تنشئ عبارات عرض مؤقتة ، لا سيما بالمقارنة مع زوجين من الاستعلامات البسيطة؟

أيضًا ، هل هناك طريقة لجعل هذه المشاهدات دائمة في تعريف قاعدة البيانات الخاص بي ، ثم ربط قيمة باسم المستخدم لكل جلسة؟ وبهذه الطريقة ، ليس من الضروري إنشاء كل هذه المشاهدات في كل مرة يقوم فيها المستخدم بتحميل صفحة.

هل كانت مفيدة؟

المحلول

العديد من المشاكل مع هذا النهج:

  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 إلا إلى مجموعة معينة ، وإلا فسيكون ذلك ضروريًا.

يمكن استخلاص هذا إلى رؤية أقل تعقيدًا قليلاً يمكن استخدامها لتسهيل التحقق من أذونات التحديث والحذف:

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 objects SET foo='bar' WHERE id=42 AND EXISTS
(SELECT NULL FROM AllowedUserGroup 
 WHERE alloweduser='Bob' AND allowedgroup = objects.group_)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top