Shiro笔记七:自定义Shiro Filter过滤器
shiro自带的Filter的问题
- shiro有自带的过滤器在DefaultFilter里面,但是有个问题。
filterChainDefinitionMap.put("/admin/**",“roles[admin,root]”);//中括号里面的是角色的名字
这里面的问题是:只有当用户属于admin和root角色时,才能访问这个路径,如果只有root角色或者只有admin角色,是不能访问的。相当于hasAllRole()
- 现在的需求是:只需要有其中一个角色就能满足访问。这就需要自定义Filter
自定义Filter,继承AuthorizationFilter,重写里面的isAccessAllowed方法。
public class CustomRolesOrAuthorizationFilter extends AuthorizationFilter {
public CustomRolesOrAuthorizationFilter(){
}
@Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
Subject subject = this.getSubject(request, response);
//获取当前访问路径所需要的角色集合
String[] rolesArray = (String[])((String[])mappedValue);
if (rolesArray != null && rolesArray.length != 0) {
Set<String> roles = CollectionUtils.asSet(rolesArray);
//当前subject是roles中的任意一个,则有权访问。
for(String role:roles){
if(subject.hasRole(role)){
return true;
}
}
return false;
} else {
return true;
}
}
}
- 修改调用的过滤器链
filterChainDefinitionMap.put("/admin/**","roleOrFilter[admin,root]");//中括号里面的是角色的名字。
使用Redis整合CacheManager
- 使用redis原因
授权的时候每次都去查询数据库,对于频繁访问接口,性能和响应速度比较慢,使用缓存代替之。
- 解决方案:
一是:在业务代码查询数据库的时候,添加进程缓存。
二是:使用Redis缓存。
- 使用Redis缓存步骤:
1、添加依赖,shiro+redis的缓存插件
<!-- shiro+redis缓存插件 -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.1.0</version>
</dependency>
- 编写redis配置类
/**
* 配置RedisManager
* @return
*/
public RedisManager getRedisManager(){
RedisManager redisManager=new RedisManager();
redisManager.setHost("localhost");
redisManager.setPort(6379);
redisManager.setDatabase(1);
return redisManager;
}
- 将Redis配置整合到Shiro的CacheManager
/**
* 配置CacheManager的具体实现类
* @return
*/
public RedisCacheManager cacheManager(){//RedisCacheManager实现了CacheManager的接口
RedisCacheManager redisCacheManager=new RedisCacheManager();
redisCacheManager.setRedisManager(getRedisManager());
//设置过期时间20s
redisCacheManager.setExpire(20);
return redisCacheManager;
}
4、让整合redis的cacheManager作为shiro的缓存方案。在SecurityManager里面配置
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
securityManager.setSessionManager(sessionManager());
//使用自定义的cacheManager
securityManager.setCacheManager(cacheManager());//此处添加缓存配置。
//推荐放到最后,不然某些版本不生效
securityManager.setRealm(customRealm());
return securityManager;
}
使用Redis整合SessionManager
- 为什么要对Session持久化
重启应用,用户无感知,可以继续以原先的状态继续访问。
- 持久化
1、使用Redis持久化,结合Shiro的RedisSessionDAO进行持久化
2、使用RedisSessionDAO加载Redis组件。
3、使用SessionManager加载RedisSessionDao。
4、注意实体类要进行序列化
/**
* 自定义redis持久化
* @return
*/
public RedisSessionDAO redisSessionDAO(){
RedisSessionDAO redisSessionDAO=new RedisSessionDAO();
redisSessionDAO.setRedisManager(getRedisManager());
redisSessionDAO.setExpire(20);
return redisSessionDAO;
}
SessionManager加载RedisSessionDao
/**
* 设置会话,自定义Session
* @return
*/
@Bean
public SessionManager sessionManager(){
CustomSessionManager customSessionManager=new CustomSessionManager();
//设置会话超时时间,单位是毫秒,默认是30分钟
//customSessionManager.setGlobalSessionTimeout(200000);
//配置session持久化
customSessionManager.setSessionDAO(redisSessionDAO());
return customSessionManager;
}
ShiroConfig中常用Bean类配置
- LifecycleBeanPostProcessor
作用:管理shiro一些bean的生命周期 即bean初始化 与销毁,注意管理的只是Shiro的Bean.
/**
* 作用:管理shiro一些bean的生命周期 即bean初始化 与销毁
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
- AuthorizationAttributeSourceAdvisor
作用:加入注解的使用,不加入这个AOP注解不生效(shiro的注解 例如 @RequiresGuest)
/**
* 作用:加入注解的使用,不加入这个AOP注解不生效(shiro的注解 例如 @RequiresGuest)
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
- DefaultAdvisorAutoProxyCreator
作用: 用来扫描上下文寻找所有的Advistor(通知器), 将符合条件的Advisor应用到切入点的Bean中,需
要在LifecycleBeanPostProcessor创建后才可以创建
/**
* 作用: 用来扫描上下文寻找所有的Advistor(通知器), 将符合条件的Advisor应用到切入点的Bean中,需
* 要在LifecycleBeanPostProcessor创建后才可以创建
* @return
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setUsePrefix(true);
return defaultAdvisorAutoProxyCreator;
}