4

アクセス制御システムを作成しようとしています。

アクセスを制御しようとしているテーブルがどのように見えるかを簡略化した例を次に示します。

things table:
id   group_id   name
1    1          thing 1
2    1          thing 2
3    1          thing 3
4    1          thing 4
5    2          thing 5

アクセス制御テーブルは次のようになります。

access table:
user_id  type   object_id  access
1        group  1          50
1        thing  1          10
1        thing  2          100

アクセスは、「モノ」の ID を直接指定して付与するか、グループ ID を指定してモノのグループ全体に付与することができます。上記の例では、ユーザー 1 にはグループ 1 へのアクセス レベル 50 が付与されています。これは、個々のものへのより具体的なアクセスを許可する他のルールがない限り適用されます。

特定のユーザーのアクセス レベルと共にリスト (ID のみで問題ありません) を返すクエリが必要です。したがって、上記の例を使用すると、ユーザー ID 1 に対して次のようなものが必要になります。

desired result:
thing_id   access
1          10
2          100
3          50   (things 3 and 4 have no specific access rule,
4          50   so this '50' is from the group rule)
5               (thing 5 has no rules at all, so although I 
                still want it in the output, there's no access
        level for it)

私が思いつくことができる最も近いものはこれです:

SELECT * 
FROM things 
LEFT JOIN access ON 
    user_id = 1
    AND (
        (access.type = 'group' AND access.object_id = things.group_id)
        OR (access.type = 'thing' AND access.object_id = things.id)
    )

しかし、「もの」テーブルの各行に1つだけが必要な場合、複数の行が返されます。「モノ」ごとに 1 行にまとめる方法や、「グループ」ルールよりも「モノ」ルールを優先する方法がわかりません。

参考になれば、私が使用しているデータベースは PostgreSQL です。

私が見逃した情報がありましたら、お気軽にコメントを残してください。

前もって感謝します!

4

4 に答える 4

1

昨夜、これに関する論文を読みました。これを行う方法についていくつかのアイデアがあります。タイトルのリンクを使用できない場合は、Google Scholar on Limiting Disclosure in Hippocratic Databases を使用してみてください。

于 2008-10-14T11:50:57.110 に答える
1

Postgres SQL の方言はわかりませんが、次のようなものかもしれません。

select thing.*, coalesce ( ( select access
                             from   access
                             where  userid = 1
                             and    type = 'thing'
                             and    object_id = thing.id
                           ),
                           ( select access
                             from   access
                             where  userid = 1
                             and    type = 'group'
                             and    object_id = thing.group_id
                           )
                         )
from things

ちなみに私はデザインが好きではありません。アクセス テーブルを 2 つに分割することをお勧めします。

thing_access (user_id, thing_id, access)
group_access (user_id, group_id, access)

私のクエリは次のようになります。

select thing.*, coalesce ( ( select access
                             from   thing_access
                             where  userid = 1
                             and    thing_id = thing.id
                           ),
                           ( select access
                             from   group_access
                             where  userid = 1
                             and    group_id = thing.group_id
                           )
                         )
from things

アクセステーブルで外部キーを使用できるようになったため、私はこれを好みます。

于 2008-10-14T11:56:43.823 に答える
1

いくつかの良い答えがありますが、最も効率的なのはおそらく次のようなものです。

SELECT things.id, things.group_id, things.name, max(access) 
FROM things 
LEFT JOIN access ON 
        user_id = 1 
        AND (
                (access.type = 'group' AND access.object_id = things.group_id)
                OR (access.type = 'thing' AND access.object_id = things.id)
        )
group by things.id, things.group_id, things.name

これは、クエリに追加された要約を使用して、探しているものを取得するだけです。

于 2008-10-14T11:59:56.563 に答える
0

トニー:

悪い解決策ではありません。私はそれが好きです。うまくいくようです。微調整後のクエリは次のとおりです。

SELECT 
    things.*, 
    coalesce ( 
        (   SELECT access 
            FROM access 
            WHERE user_id = 1 
                AND type = 'thing' 
                AND object_id = things.id
        ), 
        (   SELECT access 
            FROM access 
            WHERE user_id = 1 
                AND type = 'group' 
                AND object_id = things.group_id 
        ) 
    ) AS access
    FROM things;

そして、結果は正しいように見えます:

 id | group_id |  name   | access 
----+----------+---------+--------
  1 |        1 | thing 1 |     10
  2 |        1 | thing 2 |    100
  3 |        1 | thing 3 |     50
  4 |        1 | thing 4 |     50
  5 |        2 | thing 5 |       

私はそれが理想的なスキーマではないという点を完全に理解しています。しかし、私はある程度それで立ち往生しています。


ヨーゼフ:

あなたの解決策は、私が遊んでいたものと非常によく似ており、私の本能(そうであるように)は、そのようにすることが可能であるべきだと教えてくれます。残念ながら、完全に正しい結果は得られません。

 id | group_id |  name   | max 
----+----------+---------+-----
  1 |        1 | thing 1 |  50
  2 |        1 | thing 2 | 100
  3 |        1 | thing 3 |  50
  4 |        1 | thing 4 |  50
  5 |        2 | thing 5 |    

「モノ 1」のアクセス レベルは、より具体的な「モノ」アクセス値 10 ではなく、より高い「グループ」アクセス値を取得しました。これが私が求めているものです。内でそれを修正する方法はないと思いますがGROUP BY、誰か提案があれば、その点で間違っていることが証明されてうれしいです.

于 2008-10-14T12:36:50.200 に答える