项目中可能出现用户登录以后,在线切换用户权限的业务场景这个时候我们发现原本已经登录的用户在切换权限后Realms中的doGetAuthorizationInfo()方法不执行,这样对于Shiro来说用户根本没有实现权限切换。
想要实现用户权限切换途径主要有两种:
1、后台实现登出再登录
2、使用同一个会话,动态的刷新授权
第一种方案有点不太优雅,这里就不做阐述,我们来说一下第二种方法:
对于Shiro来说一个用户通过登录认证以后,每一次访问需要授权验证的API时会执行一次doGetAuthorizationInfo()来获得当前用户的授权信息,以判断此处请求是否合法,但是每一次访问都要继续授权信息获取这样效率不高,因此Shiro会在第一次执行doGetAuthorizationInfo()以后将结果保存到了缓存中这样,同一会话用户下次再继续访问时可以直接读取缓存继续权限判断了。
那么我们需要做的就是当用户执行权限切换时,将AuthorizationInfo的缓存刷新,这样该用户下一次发生请求时Shiro就会重新执行Realms中的doGetAuthorizationInfo()方法来获得授权信息,这样就实现授权信息的动态刷新了。
具体操作如下:
我们先定义一个抽象的Realm类
package com.venus.dbg.opm.realm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.realm.AuthorizingRealm;
/**
* 自定义realm抽象类
* 补充清理授权缓存信息功能
* @author He Changjie
*/
public abstract class DemoAuthorizingRealm extends AuthorizingRealm {
public void clearAuthorization(){
this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
}
}
再将我们具体的认证授权类继承该抽象类
public class WebUserRealm extends DemoAuthorizingRealm {
/**
* 获取身份验证信息并返回认证信息
* 如果身份认证失败 返回null
* @param authenticationToken 用户身份信息 token
* @return 返回封装了用户信息的 AuthenticationInfo 实例
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
// ...
}
/**
* 获取授权信息
* @param principals 身份
* @return 授权信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// ...
}
}
在用户权限切换的业务逻辑中我们只需要获取当前会话的Realm对象,调用clearAuthorization()就可以清除权限缓存
RealmSecurityManager rsm = (RealmSecurityManager)SecurityUtils.getSecurityManager();
DemoAuthorizingRealm realm = (DemoAuthorizingRealm) rsm.getRealms().iterator().next();
realm.clearAuthorization();
若项目中多Realm的情况,清理授权缓存的原理也是一样的,首先我们所有自定义的Realm需要继承DemoAuthorizingRealm,再用户切换权限时获取当前会话的Realm再调用clearAuthorization()方法就可以了。