web-dev-qa-db-ja.com

階層型RBACシナリオのクエリ

階層的な役割ベースのアクセス制御(RBAC)データモデルを備えたSQLiteデータベースがあります。

このモデルでは、ユーザーは、さまざまなリソースに対して特定のアクションを直接実行するか、またはアクセス許可が割り当てられている1つ以上のロールのメンバーになることにより、アクセス許可を付与されます。さらに、役割の階層を定義できるように、役割を他の役割に割り当てることができます。

スキーマはおおよそ次のようになります。

enter image description here

階層的な役割ベースのアクセス制御システムを設計する方法-StackOverflow から)

以下のように、Rolesテーブルに「親」列の代わりにRole_Role結合テーブルがあることを除いて、

enter image description here

(上記の画像と同じ投稿から)

また、結合テーブルには「許可」列はありません。結合テーブルにレコードが存在するということは、それが許可されることを意味します。

特定のユーザーのすべての権限を取得するクエリはどのようになりますか?再帰的なCTEを使用することを想定しているのですが、よくわかりません。

編集:次の再帰CTEが他のロールに継承されたロールを取得するために機能しています。

WITH RECURSIVE
  deep_roles(role_id, parent_id, depth) AS (
    SELECT role_id, parent_id, 1 FROM role_roles WHERE role_id = ?
    UNION ALL
    SELECT rr.role_id, rr.parent_id, dr.depth+1
      FROM deep_roles dr, role_roles AS rr
     WHERE rr.role_id=dr.parent_id
       AND dr.depth < 10
  )
SELECT DISTINCT role_id, parent_id FROM deep_roles;

これが私が必要とする唯一のCTEであるかどうかはわかりませんが、それは始まりです。

2
blah238

ヒントは@ CL。のおかげです。それをビューにして、特定のユーザーに対してそれに対してクエリを実行できるようにしました。

CREATE VIEW user_permissions_deep AS
SELECT DISTINCT user_id, permission_id
FROM (
    SELECT urd.user_id user_id, pr.permission_id permission_id, urd.role_id role_id, urd.parent_id parent_role
    FROM (
        WITH RECURSIVE
          deep_roles(user_id, role_id, parent_id, depth) AS (
            SELECT ru.user_id, rr.role_id, rr.parent_id, 0 depth
            FROM role_roles rr
            INNER JOIN role_users ru ON rr.role_id = ru.role_id
            UNION
            SELECT dr.user_id, rr.role_id, rr.parent_id, dr.depth+1
            FROM deep_roles dr, role_roles rr
            WHERE rr.role_id=dr.parent_id
            AND dr.depth < 10
          )
        SELECT user_id, role_id, parent_id FROM deep_roles
        WHERE depth > 0
        UNION
        SELECT user_id, role_id, null parent_id
        FROM role_users
    ) AS urd
    INNER JOIN permission_roles pr
        ON pr.role_id = urd.role_id
        OR pr.role_id = urd.parent_id
    UNION
    SELECT user_id, permission_id, null role_id, null parent_id
    FROM permission_users
) AS upd
INNER JOIN permission p ON upd.permission_id = p.id;

深度チェックを維持する必要があることがわかりました。そうしないと、ロール継承チェーンにサイクルがあった場合にループが終了しません。

これをどのように改善できるかについて誰か提案があれば、私に知らせてください!

1
blah238