项目源码:https://github.com/weimingge14/Shiro-project
演示地址:http://liweiblog.duapp.com/Shiro-project/login
用户名:admin,密码:123456
用户名:liwei,密码:123456
用户名:huzhenyu,密码:123456
我们在验证用户具有某些权限的时候,常常会调用自定义 Realm 的授权方法,这个授权方法里面常常要进行数据库查询的。在一个用户权限不会经常变更的情况下,如果不对授权的方法增加缓存,每次检查权限都去查询数据库是很浪费资源的。
步骤1:添加 ehcache 依赖
<!-- 添加 shiro-ehcache 接口依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- 添加 ehcache 实现 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.2.2.21</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
步骤2:在 Spring 的 Shiro 配置中将自定义 Realm 的部分配置为可以进行缓存的
<!-- 声明一个自定义的 Realm -->
<bean id="myRealm" class="com.liwei.shiro.realm.MyRealm">
<!-- 将上面声明的密码匹配器注入到自定义 Realm 的属性中去 -->
<property name="credentialsMatcher" ref="credentialsMatcher"/>
<!-- 将自定义的权限匹配器注入到自定义 Realm 中 -->
<property name="permissionResolver" ref="permissionResolver"/>
<!-- 配置缓存相关 -->
<!-- 启用缓存 -->
<property name="cachingEnabled" value="true"/>
<!-- 开启认证缓存-->
<property name="authenticationCachingEnabled" value="true"/>
<!-- 指定认证缓存的名字(与 ehcache.xml 中声明的相同) -->
<property name="authenticationCacheName" value="shiro-authenticationCache"/>
<!--开启授权缓存-->
<property name="authorizationCachingEnabled" value="true"/>
<!-- 指定授权缓存的名字(与 ehcache.xml 中声明的相同) -->
<property name="authorizationCacheName" value="shiro-authorizationCache"/>
</bean>
步骤3:重写自定义 Realm 部分的清除缓存的方法
@Override
protected void clearCachedAuthenticationInfo(PrincipalCollection principals) {
Cache c = getAuthenticationCache();
logger.info("清除【认证】缓存之前");
for(Object o : c.keys()){
logger.info( o + " , " + c.get(o));
}
super.clearCachedAuthenticationInfo(principals);
logger.info("调用父类清除【认证】缓存之后");
for(Object o : c.keys()){
logger.info( o + " , " + c.get(o));
}
// 添加下面的代码清空【认证】的缓存
User user = (User) principals.getPrimaryPrincipal();
SimplePrincipalCollection spc = new SimplePrincipalCollection(user.getUsername(),getName());
super.clearCachedAuthenticationInfo(spc);
logger.info("添加了代码清除【认证】缓存之后");
int cacheSize = c.keys().size();
logger.info("【认证】缓存的大小:" + c.keys().size());
if (cacheSize == 0){
logger.info("说明【认证】缓存被清空了。");
}
}
@Override
protected void clearCachedAuthorizationInfo(PrincipalCollection principals) {
logger.info("清除【授权】缓存之前");
Cache c = getAuthorizationCache();
for(Object o : c.keys()){
logger.info( o + " , " + c.get(o));
}
super.clearCachedAuthorizationInfo(principals);
logger.info("清除【授权】缓存之后");
int cacheSize = c.keys().size();
logger.info("【授权】缓存的大小:" + cacheSize);
for(Object o : c.keys()){
logger.info( o + " , " + c.get(o));
}
if(cacheSize == 0){
logger.info("说明【授权】缓存被清空了。");
}
}
此时可以打开 MyBatis 的 SQL 打印的配置。
log4j.logger.com.liwei.shiro.dao=TRACE
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=INFO
log4j.logger.java.sql.Statement=INFO
log4j.logger.java.sql.PreparedStatement=INFO
其中 log4j.logger.com.liwei.shiro.dao
是 MyBatis 接口文件所在的包名。