package com.gkhy.assess.framework.shiro; import com.gkhy.assess.framework.shiro.filter.JwtFilter; import com.gkhy.assess.framework.shiro.realm.UserRealm; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; import org.apache.shiro.mgt.DefaultSubjectDAO; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.crazycake.shiro.IRedisManager; import org.crazycake.shiro.RedisCacheManager; import org.crazycake.shiro.RedisClusterManager; import org.crazycake.shiro.RedisManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import javax.annotation.Resource; import javax.servlet.Filter; import java.util.HashSet; import java.util.Set; @Configuration @Slf4j public class ShiroConfig { @Resource private LettuceConnectionFactory lettuceConnectionFactory; @Bean public JwtFilter jwtFilter() { //过滤器如果加了@Compoent就没必要用这个方法了 return new JwtFilter(); } @Bean public FilterRegistrationBean registration(JwtFilter filter) { FilterRegistrationBean registration = new FilterRegistrationBean(new JwtFilter()); registration.setEnabled(true); return registration; } @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition(){ DefaultShiroFilterChainDefinition chain=new DefaultShiroFilterChainDefinition(); //放行Swagger2页面 chain.addPathDefinition("/swagger-ui.html","anon"); chain.addPathDefinition("/swagger/**","anon"); chain.addPathDefinition("/webjars/**", "anon"); chain.addPathDefinition("/swagger-resources/**","anon"); chain.addPathDefinition("/doc.html", "anon"); chain.addPathDefinition("/v2/api-docs", "anon"); chain.addPathDefinition("/favicon.ico","anon"); chain.addPathDefinition("/static/**", "anon"); // 配置shiro错误从定向问题 /error 路径的错误处理 chain.addPathDefinition("/error", "anon"); chain.addPathDefinition("/upload/**", "anon"); chain.addPathDefinition("/account/login","anon"); chain.addPathDefinition("/logout", "logout"); chain.addPathDefinition("/notice/noticeList","anon"); chain.addPathDefinition("/notice/getNoticeById","anon"); chain.addPathDefinition("/law/lawList","anon"); chain.addPathDefinition("/law/getLawById","anon"); chain.addPathDefinition("/agency/agencyList","anon"); chain.addPathDefinition("/agency/getAgencyById","anon"); chain.addPathDefinition("/system/dictType/getDictDataByType","anon"); chain.addPathDefinition("/system/agency/checkAgencyNameUnique","anon"); chain.addPathDefinition("/system/user/addAgency","anon"); chain.addPathDefinition("/system/user/checkUserNameUnique","anon"); chain.addPathDefinition("/system/user/checkPhoneUnique","anon"); chain.addPathDefinition("/system/captcha/captchaImage","anon"); chain.addPathDefinition("/system/region/regionTree","anon"); chain.addPathDefinition("/system/common/uploadFile","anon"); chain.addPathDefinition("/system/common/removeFile","anon"); //除了以上的请求外,其它请求都需要登录 chain.addPathDefinition("/**", "jwtFilter,authc"); // 需登录才能访问 // chain.addPathDefinition("/**", "anon"); // 需登录才能访问 return chain; } @Bean public DefaultWebSecurityManager securityManager(UserRealm realm){ DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); securityManager.setRealm(realm); // 关闭shiro自带的session DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); //禁用session, 不保存用户登录状态。保证每次请求都重新认证 DefaultSessionStorageEvaluator defaultSessionStorageEvaluator=new DefaultSessionStorageEvaluator(); defaultSessionStorageEvaluator.setSessionStorageEnabled(false); subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); securityManager.setSubjectDAO(subjectDAO); //自定义缓存实现,使用redis securityManager.setCacheManager(redisCacheManager()); return securityManager; } /** * 下面的代码是添加注解支持 * @return */ @Bean @DependsOn("lifecycleBeanPostProcessor") public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); /** * setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。 * 在@Controller注解的类的方法中加入@RequiresRole注解,会导致该方法无法映射请求,导致返回404。 * 加入这项配置能解决这个bug */ defaultAdvisorAutoProxyCreator.setUsePrefix(true); defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor"); return defaultAdvisorAutoProxyCreator; } @Bean public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } /** * cacheManager 缓存 redis实现 * 使用的是shiro-redis开源插件 * * @return */ public RedisCacheManager redisCacheManager() { log.info("===============(1)创建缓存管理器RedisCacheManager"); RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); //redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识) redisCacheManager.setPrincipalIdFieldName("id"); //用户权限信息缓存时间 redisCacheManager.setExpire(200000); return redisCacheManager; } /** * 来源jeecg-boot项目 * 配置shiro redisManager * 使用的是shiro-redis开源插件 * * @return */ @Bean public IRedisManager redisManager() { log.info("===============(2)创建RedisManager,连接Redis.."); IRedisManager manager; // redis 单机支持,在集群为空,或者集群无机器时候使用 add by jzyadmin@163.com if (lettuceConnectionFactory.getClusterConfiguration() == null || lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().isEmpty()) { RedisManager redisManager = new RedisManager(); redisManager.setHost(lettuceConnectionFactory.getHostName() + ":" + lettuceConnectionFactory.getPort()); //(lettuceConnectionFactory.getPort()); redisManager.setDatabase(lettuceConnectionFactory.getDatabase()); redisManager.setTimeout(0); if (!StringUtils.isEmpty(lettuceConnectionFactory.getPassword())) { redisManager.setPassword(lettuceConnectionFactory.getPassword()); } manager = redisManager; }else{ // redis集群支持,优先使用集群配置 RedisClusterManager redisManager = new RedisClusterManager(); Set portSet = new HashSet<>(); lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().forEach(node -> portSet.add(new HostAndPort(node.getHost() , node.getPort()))); //update-begin--Author:scott Date:20210531 for:修改集群模式下未设置redis密码的bug issues/I3QNIC if (StringUtils.isNotEmpty(lettuceConnectionFactory.getPassword())) { JedisCluster jedisCluster = new JedisCluster(portSet, 2000, 2000, 5, lettuceConnectionFactory.getPassword(), new GenericObjectPoolConfig()); redisManager.setPassword(lettuceConnectionFactory.getPassword()); redisManager.setJedisCluster(jedisCluster); } else { JedisCluster jedisCluster = new JedisCluster(portSet); redisManager.setJedisCluster(jedisCluster); } //update-end--Author:scott Date:20210531 for:修改集群模式下未设置redis密码的bug issues/I3QNIC manager = redisManager; } return manager; } }