import java.util.Map; import javax.servlet.Filter; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 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.filter.authc.AnonymousFilter; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.session.mgt.ServletContainerSessionManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisPassword; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.listener.PatternTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.session.data.redis.RedisOperationsSessionRepository; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.session.web.http.CookieHttpSessionIdResolver; import org.springframework.session.web.http.DefaultCookieSerializer; import org.springframework.session.web.http.HttpSessionIdResolver; import com.google.common.collect.Maps; import com.rivers.shopkeeper.config.redis.MyRedisProperties; import com.rivers.shopkeeper.utils.LocalConstants; import lombok.extern.slf4j.Slf4j; @EnableRedisHttpSession @Configuration @Slf4j public class ShiroConfig { /** * 加载属性文件数据 * * @return */ @Bean(name = "shiroProperties") public MyRedisProperties shiroProperties() { return new MyRedisProperties(); } @Bean HttpSessionIdResolver httpSessionResolver() { CookieHttpSessionIdResolver httpSessionResolver = new CookieHttpSessionIdResolver(); DefaultCookieSerializer serializer = new DefaultCookieSerializer(); serializer.setCookieName(shiroProperties().getCookieName()); httpSessionResolver.setCookieSerializer(serializer); return httpSessionResolver;// 客户端Session策略 } /** * 与Session有关设置链接 * * @return */ @Bean public RedisOperationsSessionRepository sessionRepository(ApplicationEventPublisher applicationEventPublisher) { RedisOperationsSessionRepository repository = new RedisOperationsSessionRepository(shiroRedisTemplate()); repository.setApplicationEventPublisher(applicationEventPublisher); // 设置session的有效时长 repository.setDefaultMaxInactiveInterval(shiroProperties().getSessionExpire()); return repository; } @Bean RedisMessageListenerContainer keyExpirationListenerContainer(RedisConnectionFactory connectionFactory, ExpirationListener expirationListener) { RedisMessageListenerContainer listenerContainer = new RedisMessageListenerContainer(); listenerContainer.setConnectionFactory(connectionFactory); listenerContainer.addMessageListener(expirationListener, new PatternTopic("__keyevent@" + shiroProperties().getSecondaryDatabase() + "__:expired"));// __keyevent@0__:expired // 通道0表示db0 // 根据自己的dbindex选择合适的数字 listenerContainer.setErrorHandler(e -> log.error("redis session已过期", e)); return listenerContainer; } /** * FilterRegistrationBean * * @return */ @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistration = new FilterRegistrationBean(); filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter")); filterRegistration.setEnabled(true); filterRegistration.addUrlPatterns("/*"); filterRegistration.setDispatcherTypes(DispatcherType.REQUEST); return filterRegistration; } /** * @see org.apache.shiro.spring.web.ShiroFilterFactoryBean * @return */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter() { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(securityManager()); bean.setLoginUrl("/login"); bean.setSuccessUrl("/"); bean.setUnauthorizedUrl("/401"); Map filters = Maps.newHashMap(); filters.put("authc", formAuthenticationFilter()); filters.put("user", sysUserFilter()); filters.put("anon", new AnonymousFilter()); bean.setFilters(filters); Map chains = Maps.newHashMap(); chains.put("/login", "authc"); chains.put("/logout", "logout"); chains.put("/static/**", "anon"); chains.put("/css/**", "anon"); chains.put("/js/**", "anon"); chains.put("/bootstrap/**", "anon"); chains.put("/images/**", "anon"); chains.put("/error/**", "anon"); chains.put("/401", "anon"); chains.put("/druid/**", "anon"); chains.put("/authenticated", "authc"); chains.put("/s/**", "user"); chains.put("/", "user"); bean.setFilterChainDefinitionMap(chains); return bean; } @Bean public FormAuthenticationFilter formAuthenticationFilter() { return new FormAuthenticationFilter(); } @Bean public SysUserFilter sysUserFilter() { return new SysUserFilter(); } /** * 权限管理器 * * @return */ @Bean(name = "securityManager") public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); // 数据库认证的实现 manager.setRealm(shiroDbRealm()); // session 管理器 manager.setSessionManager(sessionManager()); // 缓存管理器 manager.setCacheManager(shrioRedisCacheManager()); // TODO:暂时未用 // manager.setRememberMeManager(rememberMeManager()); return manager; } // /** // * cookie对象; // * // * @return // */ // @Bean // public SimpleCookie rememberMeCookie() { // // 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe // SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); // // 如果httyOnly设置为true,则客户端不会暴露给客户端脚本代码,使用HttpOnly cookie有助于减少某些类型的跨站点脚本攻击; // simpleCookie.setHttpOnly(true); // // // simpleCookie.setMaxAge(2592000); // return simpleCookie; // } // // /** // * cookie管理对象; // * // * @return // */ // @Bean // public CookieRememberMeManager rememberMeManager() { // CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); // byte[] cipherKey = Base64.decode("wGiHplamyXlVB11UXWol8g=="); // cookieRememberMeManager.setCipherKey(cipherKey); // cookieRememberMeManager.setCookie(rememberMeCookie()); // return cookieRememberMeManager; // } /** * DefaultWebSessionManager * * @return */ @Bean(name = "sessionManager") public ServletContainerSessionManager sessionManager() { ServletContainerSessionManager sessionManager = new ServletContainerSessionManager(); return sessionManager; } /** * @see UserRealm--->AuthorizingRealm * @return */ @Bean @DependsOn(value = {"lifecycleBeanPostProcessor", "shrioRedisCacheManager"}) public ShiroDbRealm shiroDbRealm() { ShiroDbRealm userRealm = new ShiroDbRealm(); userRealm.setCacheManager(shrioRedisCacheManager()); userRealm.setCachingEnabled(true); userRealm.setAuthenticationCachingEnabled(false); userRealm.setAuthorizationCachingEnabled(true); return userRealm; } @Bean(name = "shrioRedisCacheManager") @DependsOn(value = "shiroRedisTemplate") public ShrioRedisCacheManager shrioRedisCacheManager() { ShrioRedisCacheManager cacheManager = new ShrioRedisCacheManager(shiroRedisTemplate()); cacheManager.createCache(LocalConstants.SHIRO_REDIS); return cacheManager; } @Bean(name = "shiroRedisTemplate") public RedisTemplate shiroRedisTemplate() { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(secondaryRedisConnectionFactory()); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new RedisObjectSerializer()); return template; } @Bean(name = "secondaryRedisConnectionFactory") @DependsOn(value = "shiroProperties") public RedisConnectionFactory secondaryRedisConnectionFactory() { // 单机版配置 RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(shiroProperties().getHost(), shiroProperties().getPort()); redisStandaloneConfiguration.setDatabase(shiroProperties().getSecondaryDatabase()); redisStandaloneConfiguration.setPassword(RedisPassword.of(shiroProperties().getPassword())); // 集群版配置 // RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(); // String[] serverArray = clusterNodes.split(","); // Set nodes = new HashSet(); // for (String ipPort : serverArray) { // String[] ipAndPort = ipPort.split(":"); // nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1]))); // } // redisClusterConfiguration.setPassword(RedisPassword.of(password)); // redisClusterConfiguration.setClusterNodes(nodes); // redisClusterConfiguration.setMaxRedirects(maxRedirects); // 客户端配置 GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();// 连接池配置 poolConfig.setMaxIdle(shiroProperties().getLettuce().getPool().getMaxIdle()); poolConfig.setMaxTotal(shiroProperties().getLettuce().getPool().getMaxActive()); poolConfig.setMaxWaitMillis(shiroProperties().getLettuce().getPool().getMaxWait().toMillis()); poolConfig.setMinIdle(shiroProperties().getLettuce().getPool().getMinIdle()); LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder() .poolConfig(poolConfig).commandTimeout(shiroProperties().getLettuce().getShutdownTimeout()).build(); LettuceConnectionFactory redisConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration); log.info("1.初始化Redis缓存服务器(登录用户Session及Shiro缓存管理)... ..."); return redisConnectionFactory; } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持; * * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager()); return authorizationAttributeSourceAdvisor; } @Bean @DependsOn(value = {"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultCreator = new DefaultAdvisorAutoProxyCreator(); defaultCreator.setProxyTargetClass(true); return defaultCreator; } }