ShiroConfiguration
package com.energy.common.config; import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.Filter; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.cache.ehcache.EhCacheManager; 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.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import com.energy.common.util.MyFormAuthenticationFilter; import com.energy.common.util.MyShiroRealm; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; /** * shiro配置類 * * @author lit * */ @Configuration public class ShiroConfiguration { private static final Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class); /** * LifecycleBeanPostProcessor,這是個DestructionAwareBeanPostProcessor的子類, * 負責org.apache.shiro.util.Initializable類型bean的生命周期的,初始化和銷毀。 * 主要是AuthorizingRealm類的子類,以及EhCacheManager類。 * * @return */ @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { logger.info("ShiroConfiguration.getLifecycleBeanPostProcessor()"); return new LifecycleBeanPostProcessor(); } /** * HashedCredentialsMatcher,這個類是為了對密碼進行編碼的,防止密碼在數據庫里明碼保存, * 當然在登陸認證的生活,這個類也負責對form里輸入的密碼進行編碼。 * * @return */ // @Bean(name = "hashedCredentialsMatcher") // public HashedCredentialsMatcher hashedCredentialsMatcher() { // HashedCredentialsMatcher credentialsMatcher = new // HashedCredentialsMatcher(); // credentialsMatcher.setHashAlgorithmName("MD5"); // credentialsMatcher.setHashIterations(2); // credentialsMatcher.setStoredCredentialsHexEncoded(true); // return credentialsMatcher; // } /** * ShiroRealm,這是個自定義的認證類,繼承自AuthorizingRealm, 負責用戶的認證和權限的處理 * * @return */ @Bean(name = "myShiroRealm") @DependsOn("lifecycleBeanPostProcessor") public MyShiroRealm myShiroRealm() { logger.info("ShiroConfiguration.myShiroRealm()"); MyShiroRealm myShiroRealm = new MyShiroRealm(); return myShiroRealm; } /** * EhCacheManager,緩存管理,用戶登陸成功后,把用戶信息和權限信息緩存起來, * 然后每次用戶請求時,放入用戶的session中,如果不設置這個bean,每個請求都會查詢一次數據庫。 * * @return */ @Bean(name = "ehCacheManager") @DependsOn("lifecycleBeanPostProcessor") public EhCacheManager ehCacheManager() { logger.info("ShiroConfiguration.ehCacheManager()"); EhCacheManager cacheManager = new EhCacheManager(); cacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml"); return cacheManager; } @Bean(name = "rememberMeCookie") public SimpleCookie rememberMeCookie() { logger.info("ShiroConfiguration.rememberMeCookie()"); // 這個參數是cookie的名稱,對應前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); // <!-- 記住我cookie生效時間30天 ,單位秒;--> simpleCookie.setMaxAge(259200); return simpleCookie; } /** * cookie管理對象; * * @return */ @Bean(name = "rememberMeManager") public CookieRememberMeManager rememberMeManager() { logger.info("ShiroConfiguration.rememberMeManager()"); CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); return cookieRememberMeManager; } /** * SecurityManager,權限管理,這個類組合了登陸,登出,權限,session的處理,是個比較重要的類。 * * @return */ @Bean(name = "securityManager") public DefaultWebSecurityManager securityManager() { logger.info("ShiroConfiguration.getDefaultWebSecurityManager()"); DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 設置realm. securityManager.setRealm(myShiroRealm()); // <!-- 用戶授權/認證信息Cache, 采用EhCache 緩存 --> securityManager.setCacheManager(ehCacheManager()); //注入記住我管理器; securityManager.setRememberMeManager(rememberMeManager()); return securityManager; } /** * ShiroFilterFactoryBean,是個factorybean,為了生成ShiroFilter。 * 它主要保持了三項數據,securityManager,filters,filterChainDefinitionManager。 * * @return */ @Bean public ShiroFilterFactoryBean shiroFilter() { logger.info("ShiroConfiguration.shiroFilter()"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必須設置SecuritManager shiroFilterFactoryBean.setSecurityManager(securityManager()); Map<String, Filter> filtersMap = shiroFilterFactoryBean.getFilters(); filtersMap.put("authc", myFormAuthenticationFilter());// 自定義攔截器 shiroFilterFactoryBean.setFilters(filtersMap); // 攔截器 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // 配置退出過濾器,其中的具體代碼Shiro已經替我們實現了 filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); // <!-- 過濾鏈定義,從上向下順序執行,一般將 /**放在最為下邊 -->:這是一個坑呢,一不小心代碼就不好使了; // <!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問--> filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/index", "authc"); filterChainDefinitionMap.put("/**", "authc"); // 如果不設置默認會自動尋找工程根目錄下的"/login"頁面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登錄成功后要跳轉的鏈接 shiroFilterFactoryBean.setSuccessUrl("/index"); // 未授權界面; shiroFilterFactoryBean.setUnauthorizedUrl("/403"); // 加載shiroFilter權限控制規則 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public MyFormAuthenticationFilter myFormAuthenticationFilter() { MyFormAuthenticationFilter myFormAuthenticationFilter = new MyFormAuthenticationFilter(); return myFormAuthenticationFilter; } /** * DefaultAdvisorAutoProxyCreator,Spring的一個bean,由Advisor決定對哪些類的方法進行AOP代理。 * * @return */ @Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { logger.info("ShiroConfiguration.defaultAdvisorAutoProxyCreator()"); DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator(); daap.setProxyTargetClass(true); return daap; } /** * AuthorizationAttributeSourceAdvisor,shiro里實現的Advisor類, * 內部使用AopAllianceAnnotationsAuthorizingMethodInterceptor來攔截用以下注解的方法。 * 老實說,這里注入securityManager,我不知道有啥用,從source上看不出它在什么地方會被調用。 * * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { logger.info("ShiroConfiguration.authorizationAttributeSourceAdvisor()"); AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor(); aasa.setSecurityManager(securityManager()); return aasa; } /** * ShiroDialect,為了在thymeleaf里使用shiro的標簽的bean * * @return */ @Bean(name = "shiroDialect") public ShiroDialect shiroDialect() { return new ShiroDialect(); } }
thymleaf使用shiro標簽,需要引入
<dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>1.2.1</version> </dependency>
注:問題:https://www.oschina.net/question/250720_195683
FilterChain修改如下:
// 攔截器 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // <!-- 過濾鏈定義,從上向下順序執行,一般將 /**放在最為下邊 -->:這是一個坑呢,一不小心代碼就不好使了; // <!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問--> // 配置退出過濾器,其中的具體代碼Shiro已經替我們實現了 filterChainDefinitionMap.put("/", "authc"); filterChainDefinitionMap.put("/index", "authc"); filterChainDefinitionMap.put("/logout", "logout"); //filterChainDefinitionMap.put("/**", "anon"); filterChainDefinitionMap.put("/sys/**", "authc"); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/images/**", "anon"); filterChainDefinitionMap.put("/vendors/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); // 加載shiroFilter權限控制規則 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
參考博客:Apache Shiro和Spring boot的結合使用
參考博客:Spring Boot Shiro 權限信息緩存處理,記住我,thymleaf使用shiro標簽
