| package cc.mrbird.febs.common.authentication; | 
|   | 
| import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; | 
| import cc.mrbird.febs.common.properties.FebsProperties; | 
| import lombok.RequiredArgsConstructor; | 
| import org.apache.commons.lang3.StringUtils; | 
| import org.apache.shiro.codec.Base64; | 
| import org.apache.shiro.mgt.SecurityManager; | 
| import org.apache.shiro.session.SessionListener; | 
| import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; | 
| import org.apache.shiro.spring.web.ShiroFilterFactoryBean; | 
| import org.apache.shiro.web.mgt.CookieRememberMeManager; | 
| import org.apache.shiro.web.mgt.DefaultWebSecurityManager; | 
| import org.apache.shiro.web.servlet.SimpleCookie; | 
| import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; | 
| import org.crazycake.shiro.RedisCacheManager; | 
| import org.crazycake.shiro.RedisManager; | 
| import org.crazycake.shiro.RedisSessionDAO; | 
| import org.springframework.beans.factory.annotation.Value; | 
| import org.springframework.context.annotation.Bean; | 
| import org.springframework.context.annotation.Configuration; | 
| import org.springframework.util.Base64Utils; | 
|   | 
| import java.nio.charset.StandardCharsets; | 
| import java.util.ArrayList; | 
| import java.util.Arrays; | 
| import java.util.Collection; | 
| import java.util.LinkedHashMap; | 
|   | 
| /** | 
|  * Shiro 配置类 | 
|  * | 
|  * @author MrBird | 
|  */ | 
| @Configuration | 
| @RequiredArgsConstructor | 
| public class ShiroConfig { | 
|   | 
|     private final FebsProperties febsProperties; | 
|   | 
|     @Value("${spring.redis.host}") | 
|     private String host; | 
|     @Value("${spring.redis.port}") | 
|     private int port; | 
|     @Value("${spring.redis.password:}") | 
|     private String password; | 
|     @Value("${spring.redis.timeout}") | 
|     private int timeout; | 
|     @Value("${spring.redis.database:0}") | 
|     private int database; | 
|   | 
|     /** | 
|      * shiro 中配置 redis 缓存 | 
|      * | 
|      * @return RedisManager | 
|      */ | 
|     private RedisManager redisManager() { | 
|         RedisManager redisManager = new RedisManager(); | 
|         redisManager.setHost(host + ":" + port); | 
|         if (StringUtils.isNotBlank(password)) { | 
|             redisManager.setPassword(password); | 
|         } | 
|         redisManager.setTimeout(timeout); | 
|         redisManager.setDatabase(database); | 
|         return redisManager; | 
|     } | 
|   | 
|     private RedisCacheManager cacheManager() { | 
|         RedisCacheManager redisCacheManager = new RedisCacheManager(); | 
|         redisCacheManager.setRedisManager(redisManager()); | 
|         return redisCacheManager; | 
|     } | 
|   | 
|     @Bean | 
|     public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { | 
|         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); | 
|   | 
|         // 设置 securityManager | 
|         shiroFilterFactoryBean.setSecurityManager(securityManager); | 
|         // 登录的 url | 
|         shiroFilterFactoryBean.setLoginUrl(febsProperties.getShiro().getLoginUrl()); | 
|         // 登录成功后跳转的 url | 
|         shiroFilterFactoryBean.setSuccessUrl(febsProperties.getShiro().getSuccessUrl()); | 
|         // 未授权 url | 
|         shiroFilterFactoryBean.setUnauthorizedUrl(febsProperties.getShiro().getUnauthorizedUrl()); | 
|   | 
|         LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); | 
|         // 设置免认证 url | 
|         String[] anonUrls = StringUtils.splitByWholeSeparatorPreserveAllTokens(febsProperties.getShiro().getAnonUrl(), ","); | 
|         for (String url : anonUrls) { | 
|             filterChainDefinitionMap.put(url, "anon"); | 
|         } | 
|         // 配置退出过滤器,其中具体的退出代码 Shiro已经替我们实现了 | 
|         filterChainDefinitionMap.put(febsProperties.getShiro().getLogoutUrl(), "logout"); | 
|   | 
|         filterChainDefinitionMap.put("/api/**", "anon"); | 
|   | 
|         filterChainDefinitionMap.put("/swagger-ui.html/**", "anon"); | 
|         filterChainDefinitionMap.put("/swagger-resources/**", "anon"); | 
|         filterChainDefinitionMap.put("/v2/api-docs", "anon"); | 
|         filterChainDefinitionMap.put("/webjars/**", "anon"); | 
|         filterChainDefinitionMap.put("/wsxg", "anon"); | 
|   | 
|         // 除上以外所有 url都必须认证通过才可以访问,未通过认证自动访问 LoginUrl | 
|         filterChainDefinitionMap.put("/**", "user"); | 
|   | 
|         shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); | 
|         return shiroFilterFactoryBean; | 
|     } | 
|   | 
|     @Bean | 
|     public SecurityManager securityManager(ShiroRealm shiroRealm) { | 
|         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); | 
|         // 配置 SecurityManager,并注入 shiroRealm | 
|         securityManager.setRealm(shiroRealm); | 
|         // 配置 shiro session管理器 | 
|         securityManager.setSessionManager(sessionManager()); | 
|         // 配置 缓存管理类 cacheManager | 
|         securityManager.setCacheManager(cacheManager()); | 
|         // 配置 rememberMeCookie | 
|         securityManager.setRememberMeManager(rememberMeManager()); | 
|         return securityManager; | 
|     } | 
|   | 
|     /** | 
|      * rememberMe cookie 效果是重开浏览器后无需重新登录 | 
|      * | 
|      * @return SimpleCookie | 
|      */ | 
|     private SimpleCookie rememberMeCookie() { | 
|         // 设置 cookie 名称,对应 login.html 页面的 <input type="checkbox" name="rememberMe"/> | 
|         SimpleCookie cookie = new SimpleCookie("rememberMe"); | 
|         // 设置 cookie 的过期时间,单位为秒,这里为一天 | 
|         cookie.setMaxAge(febsProperties.getShiro().getCookieTimeout()); | 
|         return cookie; | 
|     } | 
|   | 
|     /** | 
|      * cookie管理对象 | 
|      * | 
|      * @return CookieRememberMeManager | 
|      */ | 
|     private CookieRememberMeManager rememberMeManager() { | 
|         CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); | 
|         cookieRememberMeManager.setCookie(rememberMeCookie()); | 
|         // rememberMe cookie 加密的密钥 | 
|         String encryptKey = "febs_shiro_key"; | 
|         byte[] encryptKeyBytes = encryptKey.getBytes(StandardCharsets.UTF_8); | 
|         String rememberKey = Base64Utils.encodeToString(Arrays.copyOf(encryptKeyBytes, 16)); | 
|         cookieRememberMeManager.setCipherKey(Base64.decode(rememberKey)); | 
|         return cookieRememberMeManager; | 
|     } | 
|   | 
|     @Bean | 
|     public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { | 
|         AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); | 
|         authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); | 
|         return authorizationAttributeSourceAdvisor; | 
|     } | 
|   | 
|     /** | 
|      * 用于开启 Thymeleaf 中的 shiro 标签的使用 | 
|      * | 
|      * @return ShiroDialect shiro 方言对象 | 
|      */ | 
|     @Bean | 
|     public ShiroDialect shiroDialect() { | 
|         return new ShiroDialect(); | 
|     } | 
|   | 
|     @Bean | 
|     public RedisSessionDAO redisSessionDAO() { | 
|         RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); | 
|         redisSessionDAO.setRedisManager(redisManager()); | 
|         return redisSessionDAO; | 
|     } | 
|   | 
|     /** | 
|      * session 管理对象 | 
|      * | 
|      * @return DefaultWebSessionManager | 
|      */ | 
|     @Bean | 
|     public DefaultWebSessionManager sessionManager() { | 
|         DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); | 
|         Collection<SessionListener> listeners = new ArrayList<>(); | 
|         listeners.add(new ShiroSessionListener()); | 
|         // 设置 session超时时间 | 
|         sessionManager.setGlobalSessionTimeout(febsProperties.getShiro().getSessionTimeout() * 1000L); | 
|         sessionManager.setSessionListeners(listeners); | 
|         sessionManager.setSessionDAO(redisSessionDAO()); | 
|         sessionManager.setSessionIdUrlRewritingEnabled(false); | 
|         return sessionManager; | 
|     } | 
| } |