Menu Permissions
我们首先介绍一个使用Spring Boot的菜单系统示例。 这个示例利用jCasbin来管理菜单权限。 最终,它的目标是抽象出一个专门用于菜单权限的中间件,可以扩展到Casbin支持的其他语言,如Go和Python。
1. 配置文件
你需要在policy.csv
文件中设置角色和权限管理,以及菜单项之间的父子关系。 更多详情,请参考这个GitHub仓库。
1.1 概述
使用policy.csv
,你可以灵活地配置角色权限和菜单结构,以实现细粒度的访问控制。 这个配置文件定义了不同角色对各种菜单项的访问权限,用户和角色之间的关联,以及菜单项之间的层次关系。
1.2 权限定义(策略)
- 策略规则:策略以
p
为前缀定义,指定角色(sub
)和他们在菜单项(obj
)上的权限(act
),以及规则的效果(eft
),其中allow
表示权限被授予,deny
表示权限被拒绝。
示例:
p, ROLE_ROOT, SystemMenu, read, allow
表示ROLE_ROOT
角色有权读取SystemMenu
菜单项。p, ROLE_ROOT, UserMenu, read, deny
表示ROLE_ROOT
角色被拒绝读取UserMenu
菜单项。
1.3 角色和用户关联
- 角色继承:用户-角色关系和角色层次结构以
g
为前缀定义。 这允许用户从一个或多个角色继承权限。
示例:
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管理菜单权限时,父菜单和子菜单之间的权限关系遵循特定的继承规则,有两个重要的默认规则:
父菜单权限的继承:
如果一个父菜单明确地被授予allow
权限,那么它的所有子菜单也默认为allow
权限,除非特别标记为deny
。 这意味着一旦一个父菜单是可访问的,它的子菜单默认也是可访问的。
处理没有直接权限设置的父菜单:
如果一个父菜单没有直接的权限设置(既没有明确允许也没有明确拒绝),但至少有一个子菜单明确被授予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的能力高效地管理访问权限。