階層的な役割ベースのアクセス制御(RBAC)データモデルを備えたSQLiteデータベースがあります。
このモデルでは、ユーザーは、さまざまなリソースに対して特定のアクションを直接実行するか、またはアクセス許可が割り当てられている1つ以上のロールのメンバーになることにより、アクセス許可を付与されます。さらに、役割の階層を定義できるように、役割を他の役割に割り当てることができます。
スキーマはおおよそ次のようになります。
( 階層的な役割ベースのアクセス制御システムを設計する方法-StackOverflow から)
以下のように、Rolesテーブルに「親」列の代わりにRole_Role結合テーブルがあることを除いて、
(上記の画像と同じ投稿から)
また、結合テーブルには「許可」列はありません。結合テーブルにレコードが存在するということは、それが許可されることを意味します。
特定のユーザーのすべての権限を取得するクエリはどのようになりますか?再帰的な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であるかどうかはわかりませんが、それは始まりです。
ヒントは@ 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;
深度チェックを維持する必要があることがわかりました。そうしないと、ロール継承チェーンにサイクルがあった場合にループが終了しません。
これをどのように改善できるかについて誰か提案があれば、私に知らせてください!