Menu Permissions
まず、メニューシステムを特徴とするSpring Bootの例を紹介します。 この例では、メニュー権限を管理するためにjCasbinを活用しています。 最終的には、メニュー権限に特化したミドルウェアを抽象化することを目指しており、CasbinがサポートするGoやPythonなどの他の言語にも拡張可能です。
1. 設定ファイル
policy.csv
ファイルでロールと権限の管理を設定する必要があり、メニューアイテム間の親子関係も設定します。 詳細については、このGitHubリポジトリを参照してください。
1.1 概要
policy.csv
を使用することで、役割の権限とメニュー構造を柔軟に設定し、詳細なアクセス制御を行うことができます。 この設定ファイルは、異なる役割に対する各メニューアイテムのアクセス権限、ユーザーと役割の関連付け、およびメニューアイテム間の階層関係を定義します。
1.2 権限定義(ポリシー)
- ポリシールール: ポリシーは
p
プレフィックスで定義され、役割(sub
)とその権限(act
)、メニューアイテム(obj
)、およびルールの効果(eft
)が指定されます。ここで、allow
は権限が許可され、deny
は拒否されることを示します。
例:
p, ROLE_ROOT, SystemMenu, read, allow
は、ROLE_ROOT
役割がSystemMenu
メニューアイテムに対する読み取りアクセス権を持つことを意味します。p, ROLE_ROOT, UserMenu, read, deny
は、ROLE_ROOT
役割がUserMenu
メニューアイテムに対する読み取りアクセス権を拒否されることを意味します。
1.3 役割とユーザーの関連付け
- 役割の継承: ユーザーと役割の関係および役割の階層は、
g
プレフィックスで定義されます。 これにより、ユーザーは1つまたは複数のロールから権限を継承できます。
例:
g, user, ROLE_USER
は、ユーザーuser
がROLE_USER
ロールに割り当てられていることを意味します。g, ROLE_ADMIN, ROLE_USER
は、ROLE_ADMIN
がROLE_USER
から権限を継承することを意味します。
1.4 メニューアイテムの階層
- メニューの関係: メニューアイテム間の親子関係は
g2
プレフィックスで定義され、メニューの構造を構築するのに役立ちます。
例:
g2, UserSubMenu_allow, UserMenu
は、UserSubMenu_allow
がUserMenu
のサブメニューであることを示します。g2, (NULL), SystemMenu
は、SystemMenu
にサブメニューアイテムがないことを示し、トップレベルのメニューアイテムであることを意味します。
1.5 メニュー権限の継承とデフォルトルール
jCasbinでメニューの権限を管理する際、親メニューと子メニューの権限関係は特定の継承ルールに従い、2つの重要なデフォルトルールがあります:
親メニューの権限の継承:
親メニューが明示的にallow
権限が付与されている場合、そのすべてのサブメニューも特にdeny
とマークされていない限り、デフォルトでallow
権限が適用されます。 これは、親メニューがアクセス可能になると、そのサブメニューもデフォルトでアクセス可能であることを意味します。
直接の権限設定がない親メニューの扱い:
親メニューに直接の権限設定(明示的に許可または拒否されていない)がないが、少なくとも1つのサブメニューが明示的にallow
権限が付与されている場合、その親メニューは暗黙的にallow
権限を持つと見なされます。 これにより、ユーザーはこれらのサブメニューに移動できます。
1.6 特別な権限継承ルール
権限の継承に関して、特にdeny
権限が関与するシナリオでは、システムのセキュリティと権限の正確な制御を確保するために、以下のルールに従う必要があります:
明示的な拒否とデフォルトの拒否の区別:
ROLE_ADMIN
のようなロールがAdminSubMenu_deny
のようなメニューアイテムへのアクセスを明示的に拒否されている場合(deny
とマークされている)、このロールが別のロール(例:ROLE_ROOT
)によって継承されたとしても、継承するロールは拒否されたメニューアイテムへのアクセスを許可されません。 これにより、ロールの継承によって明示的なセキュリティポリシーが迂回されることがなくなります。
デフォルト拒否権限の継承:
逆に、ロールがメニューアイテム(例:UserSubMenu_deny
)へのアクセスを拒否しているが、これがデフォルトである場合(明示的にdeny
とマークされていないが、明示的にallow
されていないため)、このロールが別のロール(例:ROLE_ADMIN
)によって継承されると、継承するロールはデフォルトのdeny
ステータスを上書きし、これらのメニューアイテムへのアクセスを許可することができます。
1.7 例の説明
ポリシー:
p, ROLE_ROOT, SystemMenu, read, allow
p, ROLE_ROOT, AdminMenu, read, allow
p, ROLE_ROOT, UserMenu, read, deny
p, ROLE_ADMIN, UserMenu, read, allow
p, ROLE_ADMIN, AdminMenu, read, allow
p, ROLE_ADMIN, AdminSubMenu_deny, read, deny
p, ROLE_USER, UserSubMenu_allow, read, allow
g, user, ROLE_USER
g, admin, ROLE_ADMIN
g, root, ROLE_ROOT
g, ROLE_ADMIN, ROLE_USER
g2, UserSubMenu_allow, UserMenu
g2, UserSubMenu_deny, UserMenu
g2, UserSubSubMenu, UserSubMenu_allow
g2, AdminSubMenu_allow, AdminMenu
g2, AdminSubMenu_deny, AdminMenu
g2, (NULL), SystemMenu
メニュー名 | ROLE_ROOT | ROLE_ADMIN | ROLE_USER |
---|---|---|---|
SystemMenu | ✅ | ❌ | ❌ |
UserMenu | ❌ | ✅ | ❌ |
UserSubMenu_allow | ❌ | ✅ | ✅ |
UserSubSubMenu | ❌ | ✅ | ✅ |
UserSubMenu_deny | ❌ | ✅ | ❌ |
AdminMenu | ✅ | ✅ | ❌ |
AdminSubMenu_allow | ✅ | ✅ | ❌ |
AdminSubMenu_deny | ✅ | ❌ | ❌ |
2. メニュー権限制御
特定のユーザー名でアクセス可能なすべてのメニューアイテムのリストは、MenuService で利用可能な findAccessibleMenus()
関数を通じて特定できます。 特定のユーザーが指定されたメニューアイテムにアクセスする権限を持っているかどうかを確認するために、checkMenuAccess()
メソッドを利用できます。 このアプローチにより、jCasbin の能力を活用してアクセス権を効率的に管理することで、メニュー権限が効果的に制御されます。