package cn.chnmuseum.party.conf;
import cn.chnmuseum.party.auth.filter.JwtFilter;
import cn.chnmuseum.party.auth.realm.MyShiroRealm;
import cn.chnmuseum.party.model.PermissionInit;
import cn.chnmuseum.party.service.PermissionInitService;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.annotation.Order;
import redis.clients.jedis.JedisPoolConfig;
import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Configuration
@Order(-2)
public class ShiroConfig {
private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
private static final String CACHE_KEY = "shiro:cache:";
@Resource
private PermissionInitService permissionInitService;
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
/**
* ShiroFilterFactoryBean 处理拦截资源文件问题。
*
* 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
*
* 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
*
*
*
* Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
*
* 3、部分过滤器可指定参数,如perms,roles
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 未授权界面
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
// 自定义拦截器
Map filtersMap = shiroFilterFactoryBean.getFilters();
filtersMap.put("jwt", new JwtFilter());
shiroFilterFactoryBean.setFilters(filtersMap);
// 权限控制map
Map filterChainDefinitionMap = new LinkedHashMap<>();
List list = this.permissionInitService.selectAll();
for (PermissionInit permissionInit : list) {
filterChainDefinitionMap.put(permissionInit.getUrl(), permissionInit.getPermissionInit());
}
//访问401和404页面不通过我们的Filter
filterChainDefinitionMap.put("/logout", "anon");
filterChainDefinitionMap.put("/verifyCode", "anon");
filterChainDefinitionMap.put("/ajaxLogin1", "anon");
filterChainDefinitionMap.put("/verifyCode1", "anon");
filterChainDefinitionMap.put("/loginByQrCode", "anon");
filterChainDefinitionMap.put("/doc.html", "anon");
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/cmRestApi/equitment/key", "anon");
filterChainDefinitionMap.put("/404", "anon");
filterChainDefinitionMap.put("/500", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean("securityManager")
public DefaultWebSecurityManager securityManager() {
logger.info("ShiroConfiguration.securityManager()");
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm
securityManager.setRealm(myShiroRealm());
// 自定义缓存实现 使用redis
securityManager.setCacheManager(redisCacheManager());
// 关闭shiro自带的session
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
securityManager.setSubjectDAO(subjectDAO);
return securityManager;
}
/**
* 身份认证realm; (这个需要自己写,账号密码校验;权限等)
*/
@Bean
public MyShiroRealm myShiroRealm() {
// //开启全局缓存配置
// myShiroRealm.setCachingEnabled(true);
// //启用身份验证缓存,即缓存AuthenticationInfo信息,默认false
// myShiroRealm.setAuthenticationCachingEnabled(true);
// //启用授权缓存,即缓存AuthorizationInfo信息,默认false
// myShiroRealm.setAuthorizationCachingEnabled(true);
//
// //为了方便操作,我们给缓存起个名字
// myShiroRealm.setAuthenticationCacheName("authcCache");
// myShiroRealm.setAuthorizationCacheName("authzCache");
//
// //注入缓存实现
// myShiroRealm.setCacheManager(redisCacheManager());
return new MyShiroRealm();
}
/**
* LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
* 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
* 主要是AuthorizingRealm类的子类,以及EhCacheManager类。 Shiro生命周期处理器
*/
@Bean
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
logger.info("ShiroConfiguration.getLifecycleBeanPostProcessor()");
return new LifecycleBeanPostProcessor();
}
/**
* DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
* 实现AOP式方法级权限检查
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
logger.info("ShiroConfiguration.defaultAdvisorAutoProxyCreator()");
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
//defaultAdvisorAutoProxyCreator.setUsePrefix(true);
// 强制使用cglib,防止重复代理和可能引起代理出错的问题
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
/**
* 开启shiro的aop注解支持. 使用代理方式; 所以需要开启代码支持;
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
logger.info("ShiroConfiguration.authorizationAttributeSourceAdvisor()");
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
/**
* 配置Redis管理器
*
* @return
* @Attention 使用的是shiro-redis开源插件
*/
@Bean
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setHost(host + ":" + port);
redisManager.setTimeout(timeout);
redisManager.setPassword(password);
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxIdle + maxActive);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
redisManager.setJedisPoolConfig(jedisPoolConfig);
return redisManager;
}
/**
* 用户授权信息Cache, 采用Redis
*/
@Bean
public RedisCacheManager redisCacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
//redisCacheManager.setKeyPrefix(CACHE_KEY);
// shiro-redis要求放在session里面的实体类必须有个id标识
//这是组成redis中所存储数据的key的一部分
redisCacheManager.setPrincipalIdFieldName("id");
//用户权限信息缓存时间
//redisCacheManager.setExpire(200000);
return redisCacheManager;
}
}