初次学习shiro是从iteye上的《跟我学shiro》,后来开始自己研究shiro的源码,发现《跟我学shiro》中对这个框架的权限对比讲的不够详细,所以把自己研究后对shiro的权限的理解写一下。
shiro框架中,权限对象的抽象接口为“org.apache.shiro.authz.Permission”。这个接口只有一个方法:implies,这个方法的输入输出与Object.equals方法很像,输入是一个Permission对象,输出则是boolean类型。含义也很明显:我这个权限对象与其它权限对象进行对比,如果验证通过,返回真,不通过,返回假。
在org.apache.shiro.realm.AuthorizingRealm类的子类中,需要实现protectedAuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)方法,在这个方法中,将为用户设置拥有的权限信息。下面将举一个简单的例子。
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollectionprincipals) {
String username = (String) super.getAvailablePrincipal(principals);
User user = userDao.findUserByUsername(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("系统:用户菜单:新增,删除,修改");
info.addStringPermission("系统:商品菜单:新增,删除,修改");
info.addStringPermission("系统:商品菜单:新增,删除,修改");
return info;
}
而在用户权限需要验证时,调用subject.checkPermission("系统:商品菜单:新增")即可以进行用户的权限验证。
下面,就讲一下权限验证的判断逻辑。
一个用户会拥有多个权限,我们在下文中,称此用户拥有的这些权限为“用户权限集合”。
用户想要执行某操作的时候,系统总是用某一权限值与此用户的用户权限集合进行比对,以判断此用户有无此权限,则我们在下文中称此“某一权限值”为“操作权限值”。
无论是用户权限集合中的权限值与操作权限值,结构都是相同的。
下面重点介绍单一权限值的结构:
单一权限值的形式如下:
系统:用户菜单:新增,删除,修改
每一个shiro中的权限值都分为2层结构
第1层由“:”分隔
“系统”、“用户菜单”、“新增,删除,修改”三项分别为第一层的元素
第1层中的元素最少有一个,可以有无限多个
如“系统”这种权限值是合法的,“系统:菜单:用户菜单:新增操作:新增用户操作”这种权限值也是合法的。
在下文中,我们成第1层中的元素为“权限1级单位”。
第2层由“,”分隔
“新增”、“删除”,“修改”分别为第二层的元素。
其实“系统”、“用户菜单”也分别为第二层的元素
第2层中的元素最少有一个,可以有无限多个
如“查询”这种权限值是合法的,“新增,查询,修改,删除”这种权限值也是合法的。
在下文中,我们称第2层中的元素为“权限2级单位”。
权限1级单位之间有前后顺序,顺序不可以颠倒。
如“系统:菜单:用户菜单”和“系统:用户菜单:菜单”两个权限值不相等。
权限2级单位之间没有前后顺序,顺序可以颠倒。
如“新增,修改,删除,查询”和“查询,新增,删除,修改”两个子权限值是相等的。
权限1级单位集合在JAVA代码中的映射形式是List,权限2级单位集合在JAVA代码中的映射形式是Set,单个权限2级单位在JAVA代码中的映射形式是String。
两个权限进行比对的时候,系统会认为每个权限都至少有1个权限1级单位和1个权限2级单位。
我下面讲的文字中“权限比对是相等的”含义是“imply结果是true”,并不代表两个权限完全一样,也可能是一个权限完全包含另一个权限。
用户权限集合和某一操作权限进行比对的具体过程是:
用户权限集合中的权限与一个操作权限值对比的时候,如果任何1个用户权限与操作权限值对比为真,则整体对比结果为真。全部对比结果都为假,则整体对比结果才为假。
权限1级单位是有顺序的,两个权限相对比的时候,权限1级单位按顺序进行对比。对比结果只有两种:真或假。如果遇到真,则继续向后判断。如果遇到假,则直接返回“权限不符合”。
如果用户权限中只包含父权限,而操作权限值是父权限加子权限,并且两个权限的父权限级别比对全部为真,那么此权限比对结果为真。
如用户权限为“系统:菜单”,操作权限为“系统:菜单:用户菜单:测试,新增,修改,删除”,则此权限比对结果为真。
这可以理解为:我需要你有子权限才可以执行,而你不止有子权限,连父权限都有,我当然允许你执行。我需要你有三把钥匙中的1把才能打开锁,而你三把钥匙都有,当然能打开。
如果操作权限中只包含父权限,而用户权限值是父权限加子权限,并且两个权限的父权限级别比对全部为真,那么此权限比对结果为假。
如操作权限为“系统:菜单”,用户权限为“系统:菜单:用户菜单:测试,新增,修改,删除”,则此权限比对结果为假。
这可以理解为:我需要你有父权限才可以执行,而你只有子权限,我当然不允许你执行。我需要你同时把三把钥匙插入1把锁,才能打开锁,而你只有1把钥匙,当然打不开。
权限2级单位是没有顺序的,两个权限2级单位进行对比的时候,是看用户权限中的所有2级单位内容,是否包含了操作权限中的所有2级单位内容。如果包含了操作权限中的所有2级单位内容,则对比结果为真,如果至少1项操作权限中的2级单位内容,在用户权限中没有,则对比结果为假。
就是判断操作权限中的所有2级单位内容集合,是否是用户权限中所有2级单位内容集合的子集,如果是子集,则对比结果为真,否则为假。
“*”可以代替某个一级权限下的所有的二级权限集合。
例如:“系统:菜单:用户菜单:*”与“系统:菜单:用户菜单:测试,新增,修改,删除”两个权限值比对是相等的。
“*”后面还可以带一级权限和二级权限,如“系统:菜单:用户菜单:*:删除ID为112的记录”在结构上是合法的。