在SpringBoot中使用Shiro安全框架配置方案:css
1,首先引入Shiro的Maven jar包:html
<!-- 權限框架 begin--> <dependency><!-- 核心 --> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.0</version> </dependency> <dependency><!-- 集成Spring --> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <dependency><!-- 緩存機制 --> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.4.0</version> </dependency> <!-- 權限框架 end-->
2,引入Shiro緩存配置:java
<!-- 在resource下新建 ehcache-shiro.xml --> <ehcache updateCheck="false" name="shiroCache"> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"/> </ehcache>
3,進行Shiro配置:git
(1),自定義受權認證:web
package com.gy.demo.config.shiro; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.gy.demo.entity.Power; import com.gy.demo.entity.User; import com.gy.demo.entity.UserLogin; import com.gy.demo.service.RolePowerService; import com.gy.demo.service.UserLoginService; import com.gy.demo.service.UserService; import jdk.nashorn.internal.parser.Token; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.SecurityUtils; import org.apache.shiro.util.ByteSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Resource; import java.util.*; /** * Description : 自定義的 Shiro 認證受權 * * 域,Shiro從Realm獲取安全數據(如用戶、角色、權限), * 就是說SecurityManager要驗證用戶身份, * 那麼它須要從Realm獲取相應的用戶進行比較以肯定用戶身份是否合法; * 也須要從Realm獲得用戶相應的角色/權限進行驗證用戶是否能進行操做; * 能夠把Realm當作DataSource,即安全數據源; * * Created by com on 2017/12/14 * * @author geYang **/ public class AuthorRealm extends AuthorizingRealm { private Logger logger = LoggerFactory.getLogger(AuthorRealm.class); @Resource private UserService userService; @Resource private UserLoginService userLoginService; @Resource private RolePowerService rolePowerService; /** * 認證(登陸時調用) 獲取身份驗證信息 * */ @Override protected AuthenticationInfo doGetAuthenticationInfo (AuthenticationToken authenticationToken) throws AuthenticationException { logger.info("Shiro: 進行身份驗證"); String accessToken = (String) authenticationToken.getPrincipal(); //根據accessToken,查詢用戶信息 User user = userService.selectOne(new EntityWrapper<User>().eq("phone", accessToken)); if(user==null){ return null; } //獲取用戶登陸密碼 UserLogin userLogin = userLoginService.selectById(user.getId()); SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user,userLogin.getPassword(), ByteSource.Util.bytes(user.getPhone()),"AuthorRealm"); return simpleAuthenticationInfo; } /** * 受權(驗證權限時調用) 根據用戶身份獲取受權信息 * */ @Override protected AuthorizationInfo doGetAuthorizationInfo (PrincipalCollection principalCollection) { logger.info("Shiro: 進行權限驗證"); //獲取用戶信息 User user = principalCollection.oneByType(User.class); //獲取到用戶權限列表 List<Power> rolePowerList = rolePowerService.getRolePower(user.getRoleId()); Set<String> powerCodeSet = new HashSet<>(); Iterator<Power> it = rolePowerList.iterator(); while (it.hasNext()){ powerCodeSet.add(it.next().getCode()); } List<String> powerCodeList = new ArrayList<>(); powerCodeList.addAll(powerCodeSet); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.addStringPermissions(powerCodeList); return simpleAuthorizationInfo; } }
(2),注入配置算法
package com.gy.demo.config.shiro; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.mgt.SecurityManager; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import java.util.LinkedHashMap; import java.util.Map; /** * Description : Shiro 權限框架配置 * * --------------------------------------------------------- * 一、應用代碼經過Subject來進行認證和受權, * 而Subject又委託給SecurityManager; * * 二、咱們須要給Shiro的SecurityManager注入Realm, * 從而讓SecurityManager能獲得合法的用戶及其權限進行判斷。 * --------------------------------------------------------- * @since 2017/12/14 * @author geYang **/ @Configuration public class ShiroConfig { private Logger logger = LoggerFactory.getLogger(ShiroConfig.class); /** * TODO 過濾文件 * @param securityManager 安全機制 * @return ShiroFilterFactoryBean * @since 2017/12/18 10:07 * @author geYang */ @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { logger.info("Shiro: 開啓攔截驗證"); ShiroFilterFactoryBean shirFilter = new ShiroFilterFactoryBean(); // SecurityManager shirFilter.setSecurityManager(securityManager); // 登錄頁面 shirFilter.setLoginUrl("/login"); // 登陸成功後要跳轉的連接 shirFilter.setSuccessUrl("/index"); // 未受權界面 shirFilter.setUnauthorizedUrl("/500.html"); // 攔截器 Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>(); // 配置退出過濾器,其中的具體的退出代碼 Shiro 已經替咱們實現了 filterChainDefinitionMap.put("/logout", "logout"); // 過濾鏈 filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); // 登陸頁面 filterChainDefinitionMap.put("/login", "anon"); // 登陸提交數據 filterChainDefinitionMap.put("/admin/adminLogin", "anon"); // 註冊界面 filterChainDefinitionMap.put("/user/register.html", "anon"); // 註冊提交數據 filterChainDefinitionMap.put("/admin/register", "anon"); // 發送郵箱驗證碼 filterChainDefinitionMap.put("/admin/sencCode", "anon"); // 判斷用戶名是否存在 filterChainDefinitionMap.put("/admin/isUsername/**", "anon"); // 判斷郵箱是否存在 filterChainDefinitionMap.put("/admin/isEmail/**", "anon"); // 公共數據 filterChainDefinitionMap.put("/public/**", "anon"); // 其餘 filterChainDefinitionMap.put("/**", "authc"); /* * * anon:全部url都均可以匿名訪問; * authc: 須要認證才能進行訪問; * user:配置記住我或認證經過能夠訪問; * */ shirFilter.setFilterChainDefinitionMap(filterChainDefinitionMap); return shirFilter; } /** * TODO 核心安全管理器;即全部與安全有關的操做都會與SecurityManager交互; *------------------------------------------------------------------------ * SecurityManager 至關於SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher; * 是Shiro的心臟;全部具體的交互都經過 SecurityManager 進行控制; * 它管理着全部Subject、且負責進行認證和受權、及會話、緩存的管理。 *------------------------------------------------------------------------- * @return SecurityManager * @since * @author geYang */ @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myRealm()); securityManager.setCacheManager(ehCacheManager()); return securityManager; } /** * 身份認證realm * */ @Bean public AuthorRealm myRealm(){ AuthorRealm myRealm = new AuthorRealm(); myRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myRealm; } /** * 憑證匹配器 * (因爲咱們的密碼校驗交給 shiro 的SimpleAuthenticationInfo進行處理了 * 因此咱們須要修改下doGetAuthenticationInfo中的代碼;) * @return HashedCredentialsMatcher */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher(){ logger.info("Shiro: 開啓憑證匹配器"); HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); // 散列算法:這裏使用MD5算法; hashedCredentialsMatcher.setHashAlgorithmName("MD5"); // 散列的次數,好比散列兩次,至關於 md5(md5("")); hashedCredentialsMatcher.setHashIterations(1); return hashedCredentialsMatcher; } /** * 緩存機制 * */ @Bean public EhCacheManager ehCacheManager(){ logger.info("Shiro: 開啓緩存機制"); EhCacheManager cacheManager = new EhCacheManager(); cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml"); return cacheManager; } /** * Shiro生命週期處理器 * @return */ @Bean("lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { logger.info("Shiro: 生命週期處理"); return new LifecycleBeanPostProcessor(); } /** * 開啓Shiro的註解(如@RequiresRoles,@RequiresPermissions),需藉助SpringAOP掃描使用Shiro註解的類,並在必要時進行安全 * 邏輯驗證 * 配置如下兩個bean(DefaultAdvisorAutoProxyCreator(可選)和AuthorizationAttributeSourceAdvisor)便可實現此功能 * @return */ @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { logger.info("Shiro: 開啓shiro註解"); DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator(); proxyCreator.setProxyTargetClass(true); return proxyCreator; } /** * shiro註解支持 */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { logger.info("Shiro: 開啓shiro註解支持"); AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } }
SpringBoot官方文檔: https://docs.spring.io/spring-boot/docs/current/reference/html/spring
項目源碼: https://gitee.com/ge.yang/SpringBootapache