package cn.wisenergy.chnmuseum.party.conf; import cn.wisenergy.chnmuseum.party.auth.filter.JwtFilter; import cn.wisenergy.chnmuseum.party.auth.realm.MyShiroRealm; import cn.wisenergy.chnmuseum.party.model.PermissionInit; import cn.wisenergy.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.mgt.SessionsSecurityManager; 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 javax.annotation.Resource; import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Configuration @Order(1) public class ShiroConfig { private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class); @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; /** * ShiroFilterFactoryBean 处理拦截资源文件问题。 * <p> * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在 * <p> * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager * <p> * <p> * <p> * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过 * <p> * 3、部分过滤器可指定参数,如perms,roles */ @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 未授权界面 shiroFilterFactoryBean.setUnauthorizedUrl("/403"); // 自定义拦截器 Map<String, Filter> filtersMap = shiroFilterFactoryBean.getFilters(); filtersMap.put("jwt", new JwtFilter()); shiroFilterFactoryBean.setFilters(filtersMap); // 权限控制map Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); List<PermissionInit> 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("/404", "anon"); filterChainDefinitionMap.put("/500", "anon"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SessionsSecurityManager 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() { 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; } /** * 配置shiro redisManager * <p> * 使用的是shiro-redis开源插件 * * @return */ public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setHost(host); redisManager.setTimeout(timeout); redisManager.setPassword(password); return redisManager; } /** * 用户授权信息Cache, 采用Redis * * @return */ public RedisCacheManager redisCacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); return redisCacheManager; } }