Apache Shiro 使用手册---转载
原文地址:http://www.360doc.com/content/12/0104/13/834950_177177202.shtml
(一)Shiro架構介紹
一、什么是Shiro?Apache Shiro是一個強大易用的Java安全框架,提供了認證、授權、加密和會話管理等功能:?
- 認證 - 用戶身份識別,常被稱為用戶“登錄”;
- 授權 - 訪問控制;
- 密碼加密 - 保護或隱藏數據防止被偷窺;
- 會話管理 - 每用戶相關的時間敏感的狀態。
對于任何一個應用程序,Shiro都可以提供全面的安全管理服務。并且相對于其他安全框架,Shiro要簡單的多。?
二、Shiro的架構介紹?
首先,來了解一下Shiro的三個核心組件:Subject, SecurityManager 和 Realms. 如下圖:?
?
Subject:即“當前操作用戶”。但是,在Shiro中,Subject這一概念并不僅僅指人,也可以是第三方進程、后臺帳戶(Daemon Account)或其他類似事物。它僅僅意味著“當前跟軟件交互的東西”。但考慮到大多數目的和用途,你可以把它認為是Shiro的“用戶”概念。?
Subject代表了當前用戶的安全操作,SecurityManager則管理所有用戶的安全操作。?
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通過SecurityManager來管理內部組件實例,并通過它來提供安全管理的各種服務。?
Realm: Realm充當了Shiro與應用安全數據間的“橋梁”或者“連接器”。也就是說,當對用戶執行認證(登錄)和授權(訪問控制)驗證時,Shiro會從應用配置的Realm中查找用戶及其權限信息。?
從這個意義上講,Realm實質上是一個安全相關的DAO:它封裝了數據源的連接細節,并在需要時將相關數據提供給Shiro。當配置Shiro時,你必須至少指定一個Realm,用于認證和(或)授權。配置多個Realm是可以的,但是至少需要一個。?
Shiro內置了可以連接大量安全數據源(又名目錄)的Realm,如LDAP、關系數據庫(JDBC)、類似INI的文本配置資源以及屬性文件等。如果缺省的Realm不能滿足需求,你還可以插入代表自定義數據源的自己的Realm實現。?
Shiro完整架構圖:?
?
除前文所講Subject、SecurityManager 、Realm三個核心組件外,Shiro主要組件還包括:?
Authenticator :認證就是核實用戶身份的過程。這個過程的常見例子是大家都熟悉的“用戶/密碼”組合。多數用戶在登錄軟件系統時,通常提供自己的用戶名(當事人)和支持他們的密碼(證書)。如果存儲在系統中的密碼(或密碼表示)與用戶提供的匹配,他們就被認為通過認證。?
Authorizer :授權實質上就是訪問控制 - 控制用戶能夠訪問應用中的哪些內容,比如資源、Web頁面等等。?
SessionManager :在安全框架領域,Apache Shiro提供了一些獨特的東西:可在任何應用或架構層一致地使用Session API。即,Shiro為任何應用提供了一個會話編程范式 - 從小型后臺獨立應用到大型集群Web應用。這意味著,那些希望使用會話的應用開發者,不必被迫使用Servlet或EJB容器了?;蛘?#xff0c;如果正在使用這些容器,開發者現在也可以選擇使用在任何層統一一致的會話API,取代Servlet或EJB機制。?
CacheManager :對Shiro的其他組件提供緩存支持。
(二)Shiro 認證
認證就是驗證用戶身份的過程。在認證過程中,用戶需要提交實體信息(Principals)和憑據信息(Credentials)以檢驗用戶是否合法。最常見的“實體/憑證”組合便是“用戶名/密碼”組合。?一、Shiro認證過程?
1、收集實體/憑據信息? Java代碼??
但是,“已記住”和“已認證”是有區別的:?
已記住的用戶僅僅是非匿名用戶,你可以通過subject.getPrincipals()獲取用戶信息。但是它并非是完全認證通過的用戶,當你訪問需要認證用戶的功能時,你仍然需要重新提交認證信息。?
這一區別可以參考亞馬遜網站,網站會默認記住登錄的用戶,再次訪問網站時,對于非敏感的頁面功能,頁面上會顯示記住的用戶信息,但是當你訪問網站賬戶信息時仍然需要再次進行登錄認證。?
2、提交實體/憑據信息?
Java代碼??
3、認證處理?
Java代碼??
相反,如果login方法執行過程中拋出異常,那么將認為認證失敗。Shiro有著豐富的層次鮮明的異常類來描述認證失敗的原因,如代碼示例。?
二、登出操作?
登出操作可以通過調用subject.logout()來刪除你的登錄信息,如:?
Java代碼??
三、認證內部處理機制?
以上,是Shiro認證在應用程序中的處理過程,下面將詳細解說Shiro認證的內部處理機制。?
?
如上圖,我們通過Shiro架構圖的認證部分,來說明Shiro認證內部的處理順序:?
1、應用程序構建了一個終端用戶認證信息的AuthenticationToken 實例后,調用Subject.login方法。?
2、Sbuject的實例通常是DelegatingSubject類(或子類)的實例對象,在認證開始時,會委托應用程序設置的securityManager實例調用securityManager.login(token)方法。?
3、SecurityManager接受到token(令牌)信息后會委托內置的Authenticator的實例(通常都是ModularRealmAuthenticator類的實例)調用authenticator.authenticate(token). ModularRealmAuthenticator在認證過程中會對設置的一個或多個Realm實例進行適配,它實際上為Shiro提供了一個可拔插的認證機制。?
4、如果在應用程序中配置了多個Realm,ModularRealmAuthenticator會根據配置的AuthenticationStrategy(認證策略)來進行多Realm的認證過程。在Realm被調用后,AuthenticationStrategy將對每一個Realm的結果作出響應。?
注:如果應用程序中僅配置了一個Realm,Realm將被直接調用而無需再配置認證策略。?
5、判斷每一個Realm是否支持提交的token,如果支持,Realm將調用getAuthenticationInfo(token); getAuthenticationInfo 方法就是實際認證處理,我們通過覆蓋Realm的doGetAuthenticationInfo方法來編寫我們自定義的認證處理。?
四、使用多個Realm的處理機制:?
1、Authenticator?
默認實現是ModularRealmAuthenticator,它既支持單一Realm也支持多個Realm。如果僅配置了一個Realm,ModularRealmAuthenticator 會直接調用該Realm處理認證信息,如果配置了多個Realm,它會根據認證策略來適配Realm,找到合適的Realm執行認證信息。?
自定義Authenticator的配置:?
Java代碼??
2、AuthenticationStrategy(認證策略)?
當應用程序配置了多個Realm時,ModularRealmAuthenticator將根據認證策略來判斷認證成功或是失敗。?
例如,如果只有一個Realm驗證成功,而其他Realm驗證失敗,那么這次認證是否成功呢?如果大多數的Realm驗證成功了,認證是否就認為成功呢?或者,一個Realm驗證成功后,是否還需要判斷其他Realm的結果?認證策略就是根據應用程序的需要對這些問題作出決斷。?
認證策略是一個無狀態的組件,在認證過程中會經過4次的調用:?
- 在所有Realm被調用之前
- 在調用Realm的getAuthenticationInfo 方法之前
- 在調用Realm的getAuthenticationInfo 方法之后
- 在所有Realm被調用之后
Shiro有3中認證策略的具體實現:?
| AtLeastOneSuccessfulStrategy | 只要有一個(或更多)的Realm驗證成功,那么認證將被視為成功 |
| FirstSuccessfulStrategy | 第一個Realm驗證成功,整體認證將被視為成功,且后續Realm將被忽略 |
| AllSuccessfulStrategy | 所有Realm成功,認證才視為成功 |
ModularRealmAuthenticator 內置的認證策略默認實現是AtLeastOneSuccessfulStrategy 方式,因為這種方式也是被廣泛使用的一種認證策略。當然,你也可以通過配置文件定義你需要的策略,如:?
Java代碼??
3、Realm的順序?
由剛才提到的認證策略,可以看到Realm在ModularRealmAuthenticator 里面的順序對認證是有影響的。?
ModularRealmAuthenticator 會讀取配置在SecurityManager里的Realm。當執行認證是,它會遍歷Realm集合,對所有支持提交的token的Realm調用getAuthenticationInfo 。?
因此,如果Realm的順序對你使用的認證策略結果有影響,那么你應該在配置文件中明確定義Realm的順序,如:?
Java代碼??
(三)Shiro 授權
授權即訪問控制,它將判斷用戶在應用程序中對資源是否擁有相應的訪問權限。?如,判斷一個用戶有查看頁面的權限,編輯數據的權限,擁有某一按鈕的權限,以及是否擁有打印的權限等等。?
一、授權的三要素?
授權有著三個核心元素:權限、角色和用戶。?
權限?
權限是Apache Shiro安全機制最核心的元素。它在應用程序中明確聲明了被允許的行為和表現。一個格式良好好的權限聲明可以清晰表達出用戶對該資源擁有的權限。?
大多數的資源會支持典型的CRUD操作(create,read,update,delete),但是任何操作建立在特定的資源上才是有意義的。因此,權限聲明的根本思想就是建立在資源以及操作上。?
而我們通過權限聲明僅僅能了解這個權限可以在應用程序中做些什么,而不能確定誰擁有此權限。?
于是,我們就需要在應用程序中對用戶和權限建立關聯。?
通常的做法就是將權限分配給某個角色,然后將這個角色關聯一個或多個用戶。?
權限聲明及粒度?
Shiro權限聲明通常是使用以冒號分隔的表達式。就像前文所講,一個權限表達式可以清晰的指定資源類型,允許的操作,可訪問的數據。同時,Shiro權限表達式支持簡單的通配符,可以更加靈活的進行權限設置。?
下面以實例來說明權限表達式。?
可查詢用戶數據?
User:view?
可查詢或編輯用戶數據?
User:view,edit?
可對用戶數據進行所有操作?
User:* 或 user?
可編輯id為123的用戶數據?
User:edit:123?
角色?
Shiro支持兩種角色模式:?
1、傳統角色:一個角色代表著一系列的操作,當需要對某一操作進行授權驗證時,只需判斷是否是該角色即可。這種角色權限相對簡單、模糊,不利于擴展。?
2、權限角色:一個角色擁有一個權限的集合。授權驗證時,需要判斷當前角色是否擁有該權限。這種角色權限可以對該角色進行詳細的權限描述,適合更復雜的權限設計。?
下面將詳細描述對兩種角色模式的授權實現。?
二、授權實現?
Shiro支持三種方式實現授權過程:?
- 編碼實現
- 注解實現
- JSP Taglig實現
1.1基于傳統角色授權實現?
當需要驗證用戶是否擁有某個角色時,可以調用Subject 實例的hasRole*方法驗證。?
Java代碼??
相關驗證方法如下:?
| Subject方法 | 描述 |
| hasRole(String roleName) | 當用戶擁有指定角色時,返回true |
| hasRoles(List<String> roleNames) | 按照列表順序返回相應的一個boolean值數組 |
| hasAllRoles(Collection<String> roleNames) | 如果用戶擁有所有指定角色時,返回true |
斷言支持?
Shiro還支持以斷言的方式進行授權驗證。斷言成功,不返回任何值,程序繼續執行;斷言失敗時,將拋出異常信息。使用斷言,可以使我們的代碼更加簡潔。?
Java代碼??
斷言的相關方法:?
| Subject方法 | 描述 |
| checkRole(String roleName) | 斷言用戶是否擁有指定角色 |
| checkRoles(Collection<String> roleNames) | 斷言用戶是否擁有所有指定角色 |
| checkRoles(String... roleNames) | 對上一方法的方法重載 |
1.2 基于權限角色授權實現?
相比傳統角色模式,基于權限的角色模式耦合性要更低些,它不會因角色的改變而對源代碼進行修改,因此,基于權限的角色模式是更好的訪問控制方式。?
它的代碼實現有以下幾種實現方式:?
1、基于權限對象的實現?
創建org.apache.shiro.authz.Permission的實例,將該實例對象作為參數傳遞給Subject.isPermitted()進行驗證。?
Java代碼??
相關方法如下:?
| Subject方法 | 描述 |
| isPermitted(Permission p) | Subject擁有制定權限時,返回treu |
| isPermitted(List<Permission> perms) | 返回對應權限的boolean數組 |
| isPermittedAll(Collection<Permission> perms) | Subject擁有所有制定權限時,返回true |
2、 基于字符串的實現?
相比笨重的基于對象的實現方式,基于字符串的實現便顯得更加簡潔。?
Java代碼??
使用冒號分隔的權限表達式是org.apache.shiro.authz.permission.WildcardPermission 默認支持的實現方式。?
這里分別代表了 資源類型:操作:資源ID?
類似基于對象的實現相關方法,基于字符串的實現相關方法:?
isPermitted(String perm)、isPermitted(String... perms)、isPermittedAll(String... perms)?
基于權限對象的斷言實現?
Java代碼??
基于字符串的斷言實現?
Java代碼??
斷言實現的相關方法?
| Subject方法 | 說明 |
| checkPermission(Permission p) | 斷言用戶是否擁有制定權限 |
| checkPermission(String perm) | 斷言用戶是否擁有制定權限 |
| checkPermissions(Collection<Permission> perms) | 斷言用戶是否擁有所有指定權限 |
| checkPermissions(String... perms) | 斷言用戶是否擁有所有指定權限 |
2、基于注解的授權實現?
Shiro注解支持AspectJ、Spring、Google-Guice等,可根據應用進行不同的配置。?
相關的注解:?
@ RequiresAuthentication?
可以用戶類/屬性/方法,用于表明當前用戶需是經過認證的用戶。?
Java代碼??
@ RequiresGuest?
表明該用戶需為”guest”用戶?
@ RequiresPermissions?
當前用戶需擁有制定權限?
Java代碼??
@RequiresRoles?
當前用戶需擁有制定角色?
@ RequiresUser?
當前用戶需為已認證用戶或已記住用戶?
3、基于JSP? TAG的授權實現?
Shiro提供了一套JSP標簽庫來實現頁面級的授權控制。?
在使用Shiro標簽庫前,首先需要在JSP引入shiro標簽:?
Java代碼??
下面一一介紹Shiro的標簽:?
guest標簽?
驗證當前用戶是否為“訪客”,即未認證(包含未記住)的用戶?
Xml代碼??
user標簽?
認證通過或已記住的用戶?
Xml代碼??
authenticated標簽?
已認證通過的用戶。不包含已記住的用戶,這是與user標簽的區別所在。?
Xml代碼??
notAuthenticated標簽?
未認證通過用戶,與authenticated標簽相對應。與guest標簽的區別是,該標簽包含已記住用戶。?
Xml代碼??
principal 標簽?
輸出當前用戶信息,通常為登錄帳號信息?
Xml代碼??
hasRole標簽?
驗證當前用戶是否屬于該角色?
Xml代碼??
lacksRole標簽?
與hasRole標簽邏輯相反,當用戶不屬于該角色時驗證通過?
Xml代碼??
hasAnyRole標簽?
驗證當前用戶是否屬于以下任意一個角色。?
Xml代碼??
hasPermission標簽?
驗證當前用戶是否擁有制定權限?
Xml代碼??
lacksPermission標簽?
與hasPermission標簽邏輯相反,當前用戶沒有制定權限時,驗證通過?
Xml代碼??
三、Shiro授權的內部處理機制?
?
1、在應用程序中調用授權驗證方法(Subject的isPermitted*或hasRole*等)?
2、Sbuject的實例通常是DelegatingSubject類(或子類)的實例對象,在認證開始時,會委托應用程序設置的securityManager實例調用相應的isPermitted*或hasRole*方法。?
3、接下來SecurityManager會委托內置的Authorizer的實例(默認是ModularRealmAuthorizer 類的實例,類似認證實例,它同樣支持一個或多個Realm實例認證)調用相應的授權方法。?
4、每一個Realm將檢查是否實現了相同的 Authorizer 接口。然后,將調用Reaml自己的相應的授權驗證方法。?
當使用多個Realm時,不同于認證策略處理方式,授權處理過程中:?
1、當調用Realm出現異常時,將立即拋出異常,結束授權驗證。?
2、只要有一個Realm驗證成功,那么將認為授權成功,立即返回,結束認證。
(四)Realm 實現
在認證、授權內部實現機制中都有提到,最終處理都將交給Real進行處理。因為在Shiro中,最終是通過Realm來獲取應用程序中的用戶、角色及權限信息的。通常情況下,在Realm中會直接從我們的數據源中獲取Shiro需要的驗證信息。可以說,Realm是專用于安全框架的DAO.?一、認證實現?
正如前文所提到的,Shiro的認證過程最終會交由Realm執行,這時會調用Realm的getAuthenticationInfo(token)方法。?
該方法主要執行以下操作:?
1、檢查提交的進行認證的令牌信息?
2、根據令牌信息從數據源(通常為數據庫)中獲取用戶信息?
3、對用戶信息進行匹配驗證。?
4、驗證通過將返回一個封裝了用戶信息的AuthenticationInfo實例。?
5、驗證失敗則拋出AuthenticationException異常信息。?
而在我們的應用程序中要做的就是自定義一個Realm類,繼承AuthorizingRealm抽象類,重載doGetAuthenticationInfo (),重寫獲取用戶信息的方法。?
Java代碼??
二、授權實現?
而授權實現則與認證實現非常相似,在我們自定義的Realm中,重載doGetAuthorizationInfo()方法,重寫獲取用戶權限的方法即可。?
Java代碼??
(五)Shiro 配置說明
Apache Shiro的配置主要分為四部分:?- 對象和屬性的定義與配置
- URL的過濾器配置
- 靜態用戶配置
- 靜態角色配置
Apache Shiro的大多數組件是基于POJO的,因此我們可以使用POJO兼容的任何配置機制進行配置,例如:Java代碼、Sping XML、YAML、JSON、ini文件等等。下面,以Spring XML的配置方式為例,并且對其中的一些配置參數進行一些簡單說明。?
Shiro對象的配置:?
主要是對Shiro各個組件的實現進行定義配置,主要組件在前文已做過簡單介紹,這里不再一一說明。?
Xml代碼??
Shiro過濾器的配置?
Shiro主要是通過URL過濾來進行安全管理,這里的配置便是指定具體授權規則定義。?
Xml代碼??
URL過濾器配置說明:?
Shiro可以通過配置文件實現基于URL的授權驗證。FilterChain定義格式:?
URL_Ant_Path_Expression = Path_Specific_Filter_Chain?
每個URL配置,表示匹配該URL的應用程序請求將由對應的過濾器進行驗證。?
例如:?
[urls]?
/index.html = anon?
/user/create = anon?
/user/** = authc?
/admin/** = authc, roles[administrator]?
/rest/** = authc, rest?
/remoting/rpc/** = authc, perms["remote:invoke"]?
URL表達式說明?
1、URL目錄是基于HttpServletRequest.getContextPath()此目錄設置?
2、URL可使用通配符,**代表任意子目錄?
3、Shiro驗證URL時,URL匹配成功便不再繼續匹配查找。所以要注意配置文件中的URL順序,尤其在使用通配符時。?
Filter Chain定義說明?
1、一個URL可以配置多個Filter,使用逗號分隔?
2、當設置多個過濾器時,全部驗證通過,才視為通過?
3、部分過濾器可指定參數,如perms,roles?
Shiro內置的FilterChain?
| Filter Name | Class |
| anon | org.apache.shiro.web.filter.authc.AnonymousFilter |
| authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
| authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
| perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
| port | org.apache.shiro.web.filter.authz.PortFilter |
| rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
| roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
| ssl | org.apache.shiro.web.filter.authz.SslFilter |
| user | org.apache.shiro.web.filter.authc.UserFilter |
總結
以上是生活随笔為你收集整理的Apache Shiro 使用手册---转载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 视频营销、B2B营销、EDM营销之营销方
- 下一篇: HDU 2836 (离散化DP+区间优化