這篇文章主要介紹“SpringBoot怎么整合Shiro實(shí)現(xiàn)權(quán)限控制”,在日常操作中,相信很多人在SpringBoot怎么整合Shiro實(shí)現(xiàn)權(quán)限控制問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”SpringBoot怎么整合Shiro實(shí)現(xiàn)權(quán)限控制”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
創(chuàng)新互聯(lián)建站長(zhǎng)期為1000+客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為鳳城企業(yè)提供專(zhuān)業(yè)的成都網(wǎng)站建設(shè)、做網(wǎng)站,鳳城網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。
Apache Shiro是一個(gè)強(qiáng)大且易用的Java安全框架,執(zhí)行身份驗(yàn)證、授權(quán)、密碼和會(huì)話管理。
shiro有個(gè)核心組件,分別為Subject、SecurityManager和Realms
Subject:相當(dāng)于當(dāng)前操作的”用戶“,這個(gè)用戶不一定是一個(gè)具體的人,是一個(gè)抽象的概念,表明的是和當(dāng)前程序進(jìn)行交互的任何東西,例如爬蟲(chóng)、腳本、等等。所有的Subject都綁定到SecurityManager上,與 Subject 的所有交互都會(huì)委托給 SecurityManager;可以把 Subject 認(rèn)為是一個(gè)門(mén)面;SecurityManager 才是實(shí)際的執(zhí)行者。
SecurityManager:這個(gè)是shiro框架的核心,所有與安全相關(guān)的操作都會(huì)與它進(jìn)行交互,它管理者所有的Subject。
Realms:充當(dāng)了Shiro與應(yīng)用安全數(shù)據(jù)間的”橋梁“,當(dāng)對(duì)用戶執(zhí)行認(rèn)證(登錄)和授權(quán)(訪問(wèn)控制)驗(yàn)證時(shí),SecurityManager 需要從 Realm 獲取相應(yīng)的用戶進(jìn)行比較以確定用戶身份是否合法;也需要從 Realm 得到用戶相應(yīng)的角色 / 權(quán)限進(jìn)行驗(yàn)證用戶是否能進(jìn)行操作。
1.2.1、Maven的配置
<!--shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.1</version> </dependency> <!--shiro整合thymeleaf--> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> <!--shiro緩存--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.7.1</version> </dependency>
shiro默認(rèn)是與jsp進(jìn)行使用的,而這里是shiro整合thymeleaf所有要導(dǎo)入shiro整合thymeleaf的jar包
1.2.2、整合需要實(shí)現(xiàn)的類(lèi)
一般來(lái)說(shuō)整合只需要完成兩個(gè)類(lèi)的實(shí)現(xiàn)即可
一個(gè)是 ShiroConfig 一個(gè)是 CustomerRealm
如果需要添加shiro緩存并且不是自帶的緩存而是redis緩存還需要進(jìn)行另外兩個(gè)類(lèi)的編寫(xiě)
一個(gè)是 RedisCache 一個(gè)是 RedisCacheManager
1.2.3、項(xiàng)目結(jié)構(gòu)
1.2.4、ShiroConfig的實(shí)現(xiàn)
未加shiro的緩存
package com.yuwen.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import com.yuwen.shiro.cache.RedisCacheManager; import com.yuwen.shiro.realm.CustomerRealm; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.realm.Realm; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; @Configuration public class ShiroConfig { //讓頁(yè)面shiro標(biāo)簽生效 @Bean public ShiroDialect shiroDialect(){ return new ShiroDialect(); } //1、創(chuàng)建shiroFilter 負(fù)責(zé)攔截所有請(qǐng)求 @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); //給filter設(shè)置安全管理 factoryBean.setSecurityManager(defaultWebSecurityManager); //配置系統(tǒng)的受限資源 //配置系統(tǒng)公共資源 全部都能訪問(wèn)的設(shè)置anon Map<String,String> map = new HashMap<>(); map.put("/main","authc");//請(qǐng)求這個(gè)資源需要認(rèn)證和授權(quán) authc表示需要認(rèn)證后才能訪問(wèn) map.put("/admin","roles[admin]"); //表示admin角色才能訪問(wèn) roles[]表示需要什么角色才能訪問(wèn) map.put("/manage","perms[user:*:*]"); //表示需要user:*:*權(quán)限才能訪問(wèn) perms[]表示需要什么權(quán)限才能訪問(wèn) //訪問(wèn)需要認(rèn)證的頁(yè)面如果未登錄會(huì)跳轉(zhuǎn)到/login路由進(jìn)行登陸 factoryBean.setLoginUrl("/login"); //訪問(wèn)未授權(quán)頁(yè)面會(huì)自動(dòng)跳轉(zhuǎn)到/unAuth路由 factoryBean.setUnauthorizedUrl("/unAuth"); factoryBean.setFilterChainDefinitionMap(map); return factoryBean; } //2、創(chuàng)建安全管理器 @Bean public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("getRealm") Realm realm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //給安全管理器設(shè)置 securityManager.setRealm(realm); return securityManager; } //3、創(chuàng)建自定義的realm @Bean public Realm getRealm(){ CustomerRealm customerRealm = new CustomerRealm(); //修改憑證校驗(yàn)匹配器 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); //設(shè)置加密算法為md5 credentialsMatcher.setHashAlgorithmName("MD5"); //設(shè)置散列次數(shù) credentialsMatcher.setHashIterations(1024); customerRealm.setCredentialsMatcher(credentialsMatcher); return customerRealm; } }
因?yàn)橐话阍跀?shù)據(jù)庫(kù)中設(shè)置明文密碼不安全,所有我這里對(duì)密碼進(jìn)行了md5加密,我的加密方式為:密碼 = 密碼+鹽+散列次數(shù) 而后進(jìn)行MD5加密 所以這里創(chuàng)建自定義的realm時(shí)需要進(jìn)行設(shè)置匹配器這樣登錄時(shí)密碼才能匹配成功
1.2.5、CustomerRealm的實(shí)現(xiàn)
package com.yuwen.shiro.realm; import com.yuwen.pojo.User; import com.yuwen.pojo.vo.ViewPerms; import com.yuwen.pojo.vo.ViewRole; import com.yuwen.service.UserService; import com.yuwen.shiro.salt.MyByteSource; 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.util.CollectionUtils; import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import java.util.List; //自定義realm public class CustomerRealm extends AuthorizingRealm { @Resource private UserService userService; //授權(quán) @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //獲取身份信息 String primaryPrincipal = (String)principalCollection.getPrimaryPrincipal(); //根據(jù)主身份信息獲取角色 和 權(quán)限信息 List<ViewRole> roles = userService.findRolesByUsername(primaryPrincipal); if (!CollectionUtils.isEmpty(roles)){ SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); roles.forEach(viewRole -> { simpleAuthorizationInfo.addRole(viewRole.getName()); //權(quán)限信息 List<ViewPerms> perms = userService.findPermsByRoleId(viewRole.getName()); if (!CollectionUtils.isEmpty(perms)){ perms.forEach(viewPerms -> { simpleAuthorizationInfo.addStringPermission(viewPerms.getPName()); }); } }); return simpleAuthorizationInfo; } return null; } //認(rèn)證 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //獲取登入的身份信息 String principal = (String) authenticationToken.getPrincipal(); User user = userService.findByUsername(principal); if (!ObjectUtils.isEmpty(user)){ //ByteSource.Util.bytes(user.getSalt()) 通過(guò)這個(gè)工具將鹽傳入 //如果身份認(rèn)證驗(yàn)證成功,返回一個(gè)AuthenticationInfo實(shí)現(xiàn); return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),new MyByteSource(user.getSalt()),this.getName()); } return null; } }
在登錄時(shí)會(huì)自動(dòng)調(diào)用這個(gè)身份驗(yàn)證 在驗(yàn)證時(shí)如果出錯(cuò),會(huì)報(bào)異常,我在controller層接收了異常并處理
controller層中登錄時(shí)的異常處理
@PostMapping("/login") public String login(String username,String password){ //獲取主體對(duì)象 Subject subject = SecurityUtils.getSubject(); try { //自動(dòng)調(diào)用CustomerRealm 類(lèi)中的身份驗(yàn)證方法 subject.login(new UsernamePasswordToken(username,password)); return "index"; }catch (UnknownAccountException e){ //接收異常并處理 e.printStackTrace(); model.addAttribute("msg","用戶名有誤,請(qǐng)重新登錄"); }catch (IncorrectCredentialsException e){//接收異常并處理 e.printStackTrace(); model.addAttribute("msg","密碼有誤,請(qǐng)重新登錄"); } return "login"; }
1.2.6、shiro緩存配置
定義了shiro緩存,用戶登錄后,其用戶信息、擁有的角色 / 權(quán)限不必每次去查,這樣可以提高效率
默認(rèn)緩存的配置
在 ShiroConfig中 的 getRealm() 方法中開(kāi)啟緩存管理
@Bean public Realm getRealm(){ CustomerRealm customerRealm = new CustomerRealm(); //開(kāi)啟緩存管理 customerRealm.setCacheManager(new EhCacheManager()); //開(kāi)啟全局緩存 customerRealm.setCachingEnabled(true); //開(kāi)啟認(rèn)證緩存 customerRealm.setAuthenticationCachingEnabled(true); customerRealm.setAuthenticationCacheName("authenticationCache"); //開(kāi)啟權(quán)限緩存 customerRealm.setAuthorizationCachingEnabled(true); customerRealm.setAuthorizationCacheName("authorizationCache"); return customerRealm; }
與reids整合的緩存這里就不說(shuō)明了,放在源碼里自己查看,源碼在下方
1.2.7、主頁(yè)index.html的設(shè)置
在這里用標(biāo)簽來(lái)判斷某些區(qū)域需要認(rèn)證或什么角色或者什么權(quán)限才能訪問(wèn)
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> <head> <meta charset="UTF-8"> <title>首頁(yè)</title> <link rel="shortcut icon" href="#"> </head> <body> <h1>index</h1> <a href="/logout">退出</a> <div> <a href="/main">main</a> | <a href="/manage">manage</a> | <a href="/admin">admin</a> </div> <!--獲取認(rèn)證信息--> 用戶:<span shiro:principal=""></span><hr> <!--認(rèn)證處理--> <span shiro:authenticated=""><hr> 顯示認(rèn)證通過(guò)內(nèi)容 </span> <span shiro:notAuthenticated=""><hr> 沒(méi)有認(rèn)證時(shí) 顯示 </span> <!--授權(quán)角色--> <span shiro:hasRole="admin"><hr> admin角色 顯示 </span> <span shiro:hasPermission="user:*:*"><hr> 具有用戶模塊的"user:*:*"權(quán)限 顯示 </span> </body> </html>
1.3.1、admin角色所有權(quán)限測(cè)試
1.3.2、無(wú)角色有權(quán)限測(cè)試
1.3.3、無(wú)角色無(wú)權(quán)限測(cè)試
到此,關(guān)于“SpringBoot怎么整合Shiro實(shí)現(xiàn)權(quán)限控制”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
分享文章:SpringBoot怎么整合Shiro實(shí)現(xiàn)權(quán)限控制
鏈接分享:http://jinyejixie.com/article32/ipippc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、虛擬主機(jī)、網(wǎng)站收錄、微信小程序、定制開(kāi)發(fā)、響應(yīng)式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)