本文是对张开涛老师的shiro授权教材、博客及代码的提炼 仅自己学习和项目集成使用 如有版权问题 请联系我删除
张老师原贴:http://jinnianshilongnian.iteye.com/blog/2020017
一、授权就是访问控制,即谁能访问哪些资源
主体:用户
资源:JSP页面、特定数据、打印机
权限:页面资源访问、数据增删改查、连打印机打印、(主体是资源的操作是否被允许,无关被谁操作)
角色:权限集合,(主体是“谁”,即操作者的角色)
隐式角色:逻辑代码中直接以角色为单位判断资源操作是否被允许
显式角色:逻辑代码中直接以权限为单位判断资源操作是否被允许
二、授权方式:
1. 编程式:通过写 if/else 授权代码块完成
2. 注解式:通过在执行的 Java 方法上放置相应的注解完成
3. JSP/GSP 标签:在 JSP/GSP 页面通过相应的标签完成
三、访问控制
1、 基于角色(隐式)
[users] zhang=123,role1,role2 wang=123,role1 |
通过 Realm 返回相应的角色信息:
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addRole("role1");
authorizationInfo.addRole("role2");
逻辑代码进行判断:
subject().hasRole("role1")
subject().hasAllRoles(Arrays.asList("role1", "role2"))
subject().hasRoles(Arrays.asList("role1", "role2", "role3"))
subject().checkRole("role1");(失败抛出异常)
subject().checkRoles("role1", "role3");(失败抛出异常)
2、 基于资源(显式)
[users] zhang=123,role1,role2 wang=123,role1 [roles] role1=user:create,user:update role2=user:create,user:delete |
通过 Realm 返回相应的权限信息
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addObjectPermission(new BitPermission("+user1+10"));
authorizationInfo.addObjectPermission(new WildcardPermission("user1:*"));
authorizationInfo.addStringPermission("+user2+10");
authorizationInfo.addStringPermission("user2:*");
逻辑代码进行判断:
subject().isPermitted("user:create")
subject().isPermittedAll("user:update", "user:delete")
subject().checkPermission("user:create");//(失败抛出异常)
subject().checkPermissions("user:view");//(失败抛出异常)
四、字符串通配符权限
“:”表示资源/操作/实例的分割;“,”表示操作的分割;“*”表示任意资源/操作/实例
五、授权流程
1、调用Subject.isPermitted*/hasRole*委托给SecurityManager然后委托给Authorizer
2、Authorizer通过PermissionResolver把字符串转换成相应的 Permission 实例
3、Realm 获取 Subject 相应的角色/权限用于匹配传入的角色/权限
4、Authorizer 判断单个Realm传入的角色/权限,或Authorizer委托ModularRealmAuthorizer进行循环判断多个Realm
六、 配置permissionResolver等组件:.ini文件或.xml文件里
[main] #自定义authorizer authorizer=org.apache.shiro.authz.ModularRealmAuthorizer #自定义permissionResolver #permissionResolver=org.apache.shiro.authz.permission.WildcardPermissionResolver permissionResolver=com.github.zhangkaitao.shiro.chapter3.permission.BitAndWildPermissionResolver authorizer.permissionResolver=$permissionResolver #自定义rolePermissionResolver rolePermissionResolver=com.github.zhangkaitao.shiro.chapter3.permission.MyRolePermissionResolver authorizer.rolePermissionResolver=$rolePermissionResolver securityManager.authorizer=$authorizer #自定义realm 一定要放在securityManager.authorizer赋值之后(因为调用setRealms会将realms设置给authorizer,并给各个Realm设置permissionResolver和rolePermissionResolver) realm=com.github.zhangkaitao.shiro.chapter3.realm.MyRealm securityManager.realms=$realm |
解释:
ModularRealmAuthorizer进行多 Realm 匹配流程:
1、 首先检查相应的 Realm是否实现了实现了 Authorizer;
2、如果实现了 Authorizer,那么接着调用其相应的isPermitted*/hasRole*接口进行匹配;
3、如果有一个 Realm 匹配那么将返回 true,否则返回 false。
如果 Realm 进行授权的话,应该继承AuthorizingRealm:
public class MyRealm extends AuthorizingRealm{…}
其流程是:
1、如果调用 hasRole*,则直接获取 AuthorizationInfo.getRoles()与传入的角色比较即可;
2、如果调用如 isPermitted(“user:view”),首先通过 PermissionResolver 将权限字符串转换成相应的 Permission 实例,默认使用 WildcardPermissionResolver,即转换为通配符的WildcardPermission;
3 、通 过AuthorizationInfo.getObjectPermissions() 得 到 Permission 实 例 集 合 ; 通 过AuthorizationInfo.getStringPermissions()得到字符串集合并通过 PermissionResolver 解析为Permission 实例;然后获取用户的角色,并通过 RolePermissionResolver 解析角色对应的权限集合(默认没有实现,可以自己提供);
4、接着调用 Permission. implies(Permission p)逐个与传入的权限比较,如果有匹配的则返回
true,否则 false。
七、组件解释
Authorizer是 Shiro API 中授权核心的入口点,提供了相应的角色/权限判断接口。SecurityManager 继承了 Authorizer 接口,且提供了 ModularRealmAuthorizer 用于多 Realm 时的授权匹配。PermissionResolver用于解析权限字符串到 Permission 实例,而 RolePermissionResolver 用于根据角色解析相应的权限集合。
八、从数据库进行授权认证
1、建表:users、user_roles、roles_permissions;
2、使用 shiro-jdbc-authorizer.ini 配置文件,需要设置jdbcRealm.permissionsLookupEnabled
为 true 来开启权限查询。