shiro权限管理基本原理和实现的整理
shiro權(quán)限管理基本原理和實(shí)現(xiàn)的整理
引言:這兩天學(xué)習(xí)了一個(gè)對(duì)權(quán)限管理的新的框架shiro,在這里做一個(gè)總結(jié),既為了幫助有需要的人,也方便自己以后來(lái)回顧。
本篇文章主要針對(duì)下面幾個(gè)關(guān)鍵點(diǎn)來(lái)說(shuō)明:
1. shiro簡(jiǎn)介
2. 集成spring,快速搭建環(huán)境
3. shiro認(rèn)證(即登錄,重點(diǎn))
4. shiro授權(quán)(重點(diǎn))
5. shiro會(huì)話管理(Session)
6. shiro緩存(remember Me)
下面就讓我來(lái)根據(jù)這六點(diǎn),詳細(xì)的說(shuō)明一下shiro的基礎(chǔ)原理和操作實(shí)現(xiàn)。
一、shiro簡(jiǎn)介
(1)什么是shiro?
Apache Shiro 是 Java 的一個(gè)安全(權(quán)限)框架。
? Shiro 可以非常容易的開(kāi)發(fā)出足夠好的應(yīng)用,其不僅可以用在
JavaSE 環(huán)境,也可以用在 JavaEE 環(huán)境。
? Shiro 可以完成:認(rèn)證、授權(quán)、加密、會(huì)話管理、與Web 集成、 緩存
等。
? 下載:下載地址
shiro的架構(gòu):
二.shiro集成spring所做的準(zhǔn)備工作,本次的案例是集成SpringMvc,一些基本的配置已經(jīng)忽略。
1.導(dǎo)入jar包
2.在web.xml里面加入shiro的過(guò)濾器
3.創(chuàng)建二個(gè)shiro的配置文件applicationContext.xml和ehcache.xml
在applicationContext.xml配置文件中,我們需要加入這么幾樣?xùn)|西:
1) 配置 SecurityManager!
2)配置 CacheManager.
<--需要加入 ehcache 的 jar 包及配置文件. --> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"><!-- Set a net.sf.ehcache.CacheManager instance here if you already have one. If not, a new onewill be creaed with a default config:<property name="cacheManager" ref="ehCacheManager"/> --><!-- If you don't have a pre-built net.sf.ehcache.CacheManager instance to inject, but you wanta specific Ehcache configuration to be used, specify that here. If you don't, a defaultwill be used.: --><property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> </bean>3)配置 Realm
<!-- 3. 配置 Realm 3.1 直接配置實(shí)現(xiàn)了 org.apache.shiro.realm.Realm 接口的 bean--> <bean id="jdbcRealm" class="com.atguigu.shiro.realms.ShiroRealm"><property name="credentialsMatcher"><bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><property name="hashAlgorithmName" value="MD5"></property><property name="hashIterations" value="1024"></property></bean></property></bean><bean id="secondRealm" class="com.atguigu.shiro.realms.SecondRealm"><property name="credentialsMatcher"><bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><property name="hashAlgorithmName" value="SHA1"></property><property name="hashIterations" value="1024"></property></bean></property></bean>4)配置 LifecycleBeanPostProcessor
4. 配置 LifecycleBeanPostProcessor. 可以自定的來(lái)調(diào)用配置在 Spring IOC 容器中 shiro bean 的生命周期方法. --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><!-- Enable Shiro Annotations for Spring-configured beans. Only run afterthe lifecycleBeanProcessor has run: -->5)啟用 IOC 容器中使用 shiro 的注解.
<!-- 5. 啟用 IOC 容器中使用 shiro 的注解. 但必須在配置了 LifecycleBeanPostProcessor 之后才可以使用. --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"depends-on="lifecycleBeanPostProcessor"/><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><property name="securityManager" ref="securityManager"/></bean>6)配置 ShiroFilter.
6.1 id 必須和 web.xml 文件中配置的 DelegatingFilterProxy 的 <filter-name> 一致.若不一致, 則會(huì)拋出: NoSuchBeanDefinitionException. 因?yàn)?Shiro 會(huì)來(lái) IOC 容器中查找和 <filter-name> 名字對(duì)應(yīng)的 filter bean.--> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager"/><property name="loginUrl" value="/login.jsp"/><property name="successUrl" value="/list.jsp"/><property name="unauthorizedUrl" value="/unauthorized.jsp"/><!-- <property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property> --><!-- 配置哪些頁(yè)面需要受保護(hù). 以及訪問(wèn)這些頁(yè)面需要的權(quán)限. 1). anon 可以被匿名訪問(wèn)2). authc 必須認(rèn)證(即登錄)后才可能訪問(wèn)的頁(yè)面. 3). logout 登出.4). roles 角色過(guò)濾器--><property name = "filterChainDefinitions"><value>/login.jsp = anon/shiro/login = anon/shiro/logout = logout/user.jsp = roles[user]/admin.jsp = roles[admin]#everything else requires authentication/** = authc</value></property></bean>---------》配置完了applicationContext.xml 我們接下來(lái)配置ehcache.xml
ehcache.xml里面配置的都是接下來(lái)我們要說(shuō)的關(guān)于緩存的一些信息,暫且可以忽略。
4.代碼實(shí)現(xiàn)。
這里我將用幾個(gè)簡(jiǎn)單的邏輯類和jsp頁(yè)面來(lái)完成對(duì)登錄授權(quán)訪問(wèn)的驗(yàn)證,為了方便,我先把全部代碼粘上,后面一一解釋。
1)創(chuàng)建兩個(gè)Realm實(shí)現(xiàn)類 繼承AuthorizingRealm
2)創(chuàng)建ShiroHandler,來(lái)處理我們要進(jìn)行的邏輯
@Controller @RequestMapping("/shiro/") public class ShiroHandler {@Autowiredprivate ShiroService shiroService;@RequestMapping("/testShiroannotation")public String testShiroannotation(HttpSession session) {shiroService.testMethod();session.setAttribute("key","value13245");return "redirect:/list.jsp";}@RequestMapping("login")public String login(@RequestParam("username")String username,@RequestParam("password")String password) {System.out.println(password);Subject currentUser = SecurityUtils.getSubject();if(!currentUser.isAuthenticated()) {UsernamePasswordToken token = new UsernamePasswordToken(username,password);token.setRememberMe(true);try {//執(zhí)行登錄currentUser.login(token);} catch (Exception e) {System.out.println("登錄失敗:"+e.getMessage());}}return "redirect:/list.jsp";} }3)創(chuàng)建業(yè)務(wù)邏輯層service
public class ShiroService {@RequiresRoles(value={"admin"})public void testMethod() {System.out.println("test service time:"+new Date());Session session =SecurityUtils.getSubject().getSession();Object val = session.getAttribute("key");System.out.println("Service SessionVal:"+val);} }4)創(chuàng)建幾個(gè)簡(jiǎn)單的網(wǎng)頁(yè),來(lái)實(shí)現(xiàn)登錄、跳轉(zhuǎn)、分配權(quán)限
admin.jsp模擬管理員才能訪問(wèn)的頁(yè)面
user.jsp模擬普通用戶訪問(wèn)的頁(yè)面
<body> User Page </body>login.jsp模擬登錄頁(yè)面
<body> Login Page<form action="shiro/login" method="post">username:<input type="text" name="username"><br><br>password: <input type="password" name = "password"><br><br><input type="submit" value="Submit"> </form> </body>unauthorized.jsp用于跳轉(zhuǎn)到?jīng)]有授權(quán)的頁(yè)面
<body> Unauthorized Page </body>list.jsp用來(lái)模擬登錄成功跳轉(zhuǎn)頁(yè)面
<body> <h4>List Page</h4> </br>WelCome:<shiro:principal></shiro:principal><shiro:hasRole name="admin"></br><a href="admin.jsp">Admin Page</a></br></shiro:hasRole><shiro:hasRole name="user"></br><a href="user.jsp">User Page</a></br></shiro:hasRole></br><a href="shiro/testShiroannotation">TestShiroannotation</a></br><a href="shiro/logout">Logout</a> </body>三、認(rèn)證(因?yàn)樯厦娲a都粘上了,所以我這里講解的時(shí)候就截取關(guān)鍵部分)
shiro的認(rèn)證,說(shuō)白了就是登錄,我們?cè)趆andler類里面有l(wèi)ogin方法
圖解:
角色:
? 身份驗(yàn)證:一般需要提供如身份 ID 等一些標(biāo)識(shí)信息來(lái)表明登錄者的身
份,如提供 email,用戶名/密碼來(lái)證明。
? 在 shiro 中,用戶需要提供 principals (身份)和 credentials(證
明)給 shiro,從而應(yīng)用能驗(yàn)證用戶身份:
? principals:身份,即主體的標(biāo)識(shí)屬性,可以是任何屬性,如用戶名、
郵箱等,唯一即可。一個(gè)主體可以有多個(gè) principals,但只有一個(gè)
Primary principals,一般是用戶名/郵箱/手機(jī)號(hào)。
? credentials:證明/憑證,即只有主體知道的安全值,如密碼/數(shù)字證
書(shū)等。
? 最常見(jiàn)的 principals 和 credentials 組合就是用戶名/密碼了
流程:
1.通過(guò)login.jsp頁(yè)面收集到用戶輸入的username和password
2.首先handler調(diào)用 Subject.login(token) 進(jìn)行登錄,其會(huì)自動(dòng)委托給SecurityManager
3. SecurityManager 負(fù)責(zé)真正的身份驗(yàn)證邏輯;它會(huì)委托給Authenticator 進(jìn)行身份驗(yàn)證;
4.Authenticator 才是真正的身份驗(yàn)證者,Shiro API 中核心的身份認(rèn)證入口點(diǎn),此處可以自定義插入自己的實(shí)現(xiàn);
5.Authenticator 可能會(huì)委托給相應(yīng)的 AuthenticationStrategy 進(jìn)行多 Realm 身份驗(yàn)證,默認(rèn) ModularRealmAuthenticator 會(huì)調(diào)用AuthenticationStrategy 進(jìn)行多 Realm 身份驗(yàn)證;
6. Authenticator 會(huì)把相應(yīng)的 token 傳入 Realm,從 Realm 獲取身份驗(yàn)證信息,如果沒(méi)有返回/拋出異常表示身份驗(yàn)證失敗了。此處
可以配置多個(gè)Realm,將按照相應(yīng)的順序及策略進(jìn)行訪問(wèn)。
7.創(chuàng)建Realm類接收handler傳來(lái)的token,完成對(duì)用戶名和密碼的校驗(yàn)(Realm類上面代碼已經(jīng)創(chuàng)建)
四、授權(quán)
Shiro 支持三種方式的授權(quán):
1– 編程式:通過(guò)寫(xiě)if/else 授權(quán)代碼塊完成
2– 注解式:通過(guò)在執(zhí)行的Java方法上放置相應(yīng)的注解完成,沒(méi)有權(quán)限將拋出相應(yīng)的異常
3– JSP/GSP 標(biāo)簽:在JSP/GSP 頁(yè)面通過(guò)相應(yīng)的標(biāo)簽完成
授權(quán)的底層原理實(shí)現(xiàn):
? 1、首先調(diào)用 Subject.isPermitted*/hasRole* 接口,其會(huì)委托給SecurityManager,而 SecurityManager 接著會(huì)委托給 Authorizer;
? 2、 Authorizer是真正的授權(quán)者,如果調(diào)用如 isPermitted(“user:view”),其首先會(huì)通過(guò)? PermissionResolver 把字符串轉(zhuǎn)換成相應(yīng)的 Permission 實(shí)例;
? 3、在進(jìn)行授權(quán)之前,其會(huì)調(diào)用相應(yīng)的 Realm 獲取 Subject 相應(yīng)的角色/權(quán)限用于匹配傳入的角色/權(quán)限;
? 4、 Authorizer 會(huì)判斷 Realm 的角色/權(quán)限是否和傳入的匹配,如果有多個(gè)Realm,會(huì)委托給 ModularRealmAuthorizer 進(jìn)行循環(huán)判斷,
如果匹配如 isPermitted*/hasRole* 會(huì)返回true,否則返回false表示 授權(quán)失敗。
兩張驗(yàn)證有關(guān)的表格:
(1)編程式的實(shí)驗(yàn)在上面realm類中代碼已經(jīng)體現(xiàn),下面我截取出主要部分。
Object credentials =null;if("admin".equals(username)) {credentials ="038bdaf98f2037b31f1e75b5b4c9b26e";}else if("user".equals(username)) {credentials ="098d2c478e9c11555ce2823231e02ec1";}(2)注解的方式實(shí)現(xiàn),可以在service的相關(guān)方法上面寫(xiě)注解,也可以直接在handler或者controller類上面寫(xiě)注解。注意:當(dāng)service類上面有@trationcal事務(wù)注解時(shí),不能在service上寫(xiě)注解,只能在controller類上寫(xiě)注解。
注解的話有下面幾種,我們選擇其中一個(gè)來(lái)舉例:
我們可以為一個(gè)service中的某個(gè)方法寫(xiě)權(quán)限注解,來(lái)限制某個(gè)用戶是否能訪問(wèn)某個(gè)方法,從而實(shí)現(xiàn)限制訪問(wèn)某個(gè)頁(yè)面的目的。
同樣,注解的方式也能在controller層使用
3)通過(guò)shiro標(biāo)簽在jsp頁(yè)面進(jìn)行授權(quán)
這里通過(guò)list.jsp頁(yè)面來(lái)進(jìn)行頁(yè)面訪問(wèn)的授權(quán)
我們可以看到,當(dāng)角色的身份誰(shuí)是admin時(shí),可以訪問(wèn)admin的頁(yè)面,是user時(shí),可以訪問(wèn)user的頁(yè)面,但是由于我們前面代碼給的權(quán)限,admin可以同時(shí)訪問(wèn)這兩個(gè)頁(yè)面,但是user就只能訪問(wèn)user的頁(yè)面而不能訪問(wèn)admin的頁(yè)面,剩下的沒(méi)有給授權(quán)限制的頁(yè)面,兩種角色都能訪問(wèn)。
五、會(huì)話管理
概述:Shiro 提供了完整的企業(yè)級(jí)會(huì)話管理功能,不依賴于底層容器(如web容器tomcat),不管 JavaSE 還是 JavaEE 環(huán)境都可以 使用,提供了會(huì)話管理、會(huì)話事件監(jiān)聽(tīng)、會(huì)話存儲(chǔ)/持久化、容器無(wú)關(guān)的集群、失效/過(guò)期支持、對(duì)Web 的透明支持、 SSO 單點(diǎn)登錄的支持 等特性。
shiro對(duì)實(shí)現(xiàn)session的增刪改查操作的主要接口是sessionDao。
如果我們需要對(duì)session實(shí)現(xiàn)增刪改查操作的話,那么我們需要增加如下配置,并且創(chuàng)建SessionDao的類
如果不需要實(shí)現(xiàn)對(duì)session的操作,那么我們來(lái)簡(jiǎn)單示范一下:
(1)我們?cè)赾ontroller中對(duì)用HttpSession對(duì)session添加key value。
六、shiro緩存
(1)緩存的話分兩種緩存:
1.Realm 緩存
? Shiro 提供了 CachingRealm,其實(shí)現(xiàn)了CacheManagerAware 接口,提供了緩存的一些基礎(chǔ)實(shí)現(xiàn);
? AuthenticatingRealm 及 AuthorizingRealm 也分別提供了對(duì)AuthenticationInfo 和 AuthorizationInfo 信息的緩
存。
2.Session 緩存
? 如 SecurityManager 實(shí)現(xiàn)了 SessionSecurityManager,其會(huì)判斷 SessionManager 是否實(shí)現(xiàn)了CacheManagerAware 接口,如果實(shí)現(xiàn)了會(huì)把CacheManager 設(shè)置給它。
? SessionManager 也會(huì)判斷相應(yīng)的 SessionDAO(如繼承自CachingSessionDAO)是否實(shí)現(xiàn)了CacheManagerAware,如果實(shí)現(xiàn)了會(huì)把 CacheManager設(shè)置給它
? 設(shè)置了緩存的 SessionManager,查詢時(shí)會(huì)先查緩存,如果找不到才查數(shù)據(jù)庫(kù)。
我們常用的緩存就是rememberMe
(2)rememberMe
概述:
? Shiro 提供了記住我(RememberMe)的功能,比如訪問(wèn)如淘寶等一些網(wǎng)站時(shí),關(guān)閉了瀏覽器,下次再打開(kāi)時(shí)還是能記住你是誰(shuí),下次訪問(wèn)時(shí)無(wú)需再登錄即可訪問(wèn),基本流程如下:
? 1、首先在登錄頁(yè)面選中 RememberMe 然后登錄成功;如果是瀏覽器登錄,一般會(huì)把 RememberMe 的Cookie 寫(xiě)到客戶端并
保存下來(lái);
? 2、關(guān)閉瀏覽器再重新打開(kāi);會(huì)發(fā)現(xiàn)瀏覽器還是記住你的;
? 3、訪問(wèn)一般的網(wǎng)頁(yè)服務(wù)器端還是知道你是誰(shuí),且能正常訪問(wèn);
? 4、但是比如我們?cè)L問(wèn)淘寶時(shí),如果要查看我的訂單或進(jìn)行支付時(shí),此時(shí)還是需要再進(jìn)行身份認(rèn)證的,以確保當(dāng)前用戶還是你。
這個(gè)比較簡(jiǎn)單,我們只需要在controller中添加如下代碼:
我們還可以在配置文件中設(shè)置時(shí)長(zhǎng):
在applicationContext.xml中的securityManager bean中添加如下代碼,value就是代表生效的時(shí)長(zhǎng),以秒為單位。
以上就是我對(duì)shiro基礎(chǔ)的一些介紹,因?yàn)檫€沒(méi)有時(shí)間深入研究,講的都比較淺顯,等后面掌握之后還會(huì)更新內(nèi)容。
總結(jié)
以上是生活随笔為你收集整理的shiro权限管理基本原理和实现的整理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: QtCreator插件开发(四)——Qt
- 下一篇: 信号完整性分析与电源完整性分析学习笔记(