當前位置:
首頁 > 最新 > Apache Shiro 的Web應用支持指南

Apache Shiro 的Web應用支持指南

為了學習和閱讀的方便,本篇內容,主要介紹包括Shiro的web.xml配置、默認過濾器、啟用與禁止過濾器、會話管理、記住我服務以及標籤庫六大部分,以便全面掌握Apache Shiro這個Java安全管理框架的web應用支持相關內容。內容有點多,可以花點時間仔細看,或收藏後閑暇時再研究。

其它相關概念和基礎原理內容,可以參考已發布的「Shiro入門系列」文章。


將Shiro集成到任何Web應用程序中的最簡單方法是在web.xml中配置Servlet ContextListe


1. Shiro1.2及更高版

在Shiro 1.2及更高版本中,標準Web應用程序通過將以下XML塊添加到web.xml來初始化Shiro:

web.xml配置截圖

這種配置假設Shiro的INI配置文件位於以下兩個位置中的任何一個,先找到那個就以哪個為準:

1)/WEB-INF/shiro.ini;

2)shiro.ini 文件在類路徑的根目錄下;.

上面的配置所完成的工作如下:

?EnvironmentLoaderListener初始化Shiro的WebEnvironment實例(它包含Shiro需要操作的所有內容,包括SecurityManager),並使其在ServletContext中可訪問。 如果您需要隨時獲得此WebEnvironment實例,則可以通過調用WebUtils.getRequiredWebEnvironment(servletContext)獲得。

?ShiroFilter將使用此WebEnvironment為任何已過濾的請求執行所有必要的安全操作。

?最後,過濾器映射的定義,確保所有請求都由ShiroFilter過濾,推薦大多數Web應用程序這樣做,以確保任何請求受保護。

注意:ShiroFiltershiro-mapping配置

通常希望在任何其他的"過濾器映射"聲明之前定義"ShiroFilte的過濾器映射",以確保Shiro也可以在這些過濾器中運行。

定製類?

默認情況下,Shiro的EnvironmentLoaderListener將基於INI的配置創建一個IniWebEnvironment實例。 如果你樂意,可通過在web.xml中指定一個ServletContext上下文參數來指定一個自定義WebEnvironment實例

自定義WebEnvironment

定製配置文件位置

IniWebEnvironment類期望讀取和載入INI配置文件。 默認情況下,該類將自動在以下兩個位置查找Shiro .ini配置(按順序):

1) /WEB-INF/shiro.ini

2) classpath:shiro.ini

並且以首先找到的為準則。

然而,如果您希望將您的配置置於其他位置,則可以使用web.xml中的另一個上下文參數指定該位置:

自定義配置文件位置

默認情況下,param值預計可以通過ServletContext.getResource方法定義的規則解析。 例如,/WEB-INF/some/path/shiro.ini

但是,您也可以通過使用Shiro的ResourceUtils類支持的適當的資源前綴來指定特定的文件系統、類路徑或URL位置,例如:

1)file:/home/foobar/myapp/shiro.ini

2)classpath:com/foo/bar/shiro.ini

3)url:http://confighost.mycompany.com/myapp/shiro.ini

1.Shiro1.1及更早版

在1.1或更早版本的Web應用程序中啟用Shiro的最簡單方法是定義IniShiroFilter並指定過濾器映射:

此定義假定您的INI配置位於類路徑根目錄的shiro.ini文件中(例如classpath:shiro.ini)。

定製路徑

如果您不想將INI配置置於/WEB-INF/shiro.ini或classpath:shiro.ini中,則可以根據需要指定自定義資源位置。 添加configPath init-param並指定資源位置:

不合格(無模式或"非前綴")configPath值被假定為ServletContext資源路徑,可通過ServletContext.getResource方法定義的規則解析。

注意:Shiro 1.2+ ServletContext資源路徑問題

ServletContext資源路徑在Shiro 1.2和更高版本中可用。在1.1及更早版本中,所有的configPath定義都必須指定一個classpath、file:或url:前綴。

您還可分別classpath:、url:或file:前綴來指示其他非ServletContext資源位置相應的類路徑、url 或文件系統的位置。例如:

內聯配置

最後,也可以將INI配置嵌入到web.xml中,而不需要使用INI文件。 您可以通過使用config init-param而不是configPath來完成此操作

對於小型應用程序或簡單應用程序,內聯配置通常很好,但由於以下原因,將其外部化在專用shiro.ini文件中通常更方便:

?可能會編輯很多安全配置,並且不希望將修訂控制"噪音"添加到web.xml文件中;

?可能希望將安全配置從web.xml配置的其餘部分中分離出來;

?安全配置可能會變大,您希望保持web.xml精簡併易於閱讀;

?有一個複雜的構建系統,可能需要在多個位置引用相同的shiro配置。

用哪一種配置,這取決於你——以對你的項目有意義(實際場景)為準。


除了前面配置章節(查閱已發布的Shiro配置詳解部分)中已經描述的標準[main], [users] 和[roles]部分之外,您還可以在shiro.ini文件中指定特定於Web的url部分:

[urls]部分允許您執行任何我們所見過的任何Web框架中不存在的功能:可以為應用程序中的任何匹配URL路徑定義特別的過濾器鏈

這比你在web.xml中通常定義過濾器鏈的方式更靈活、更強大、更簡潔:即使你從來沒有使用過Shiro提供的任何其他特性,且僅使用這個功能(URL配置),它本身也會使其值得使用。

下面的內容,在「Shiro配置詳解」篇中已經講過,這裡為了閱讀的連續性,再次在此進行描述:

1) [urls]

[urls]部分中每行的格式如下:

_URL_Ant_Path_Expression_= _Path_Specific_Filter_Chain_

示例如下:

接下來我們將闡述這些行的意思。

等號(=)左側的標記是相對於Web應用程序的上下文根的Ant式路徑表達式。

例如,假設您有以下[urls]行:

/account/** = ssl, authc

此行描述的是:"對我的應用程序/account路徑或其任何子路徑(/account/foo,/account/bar/baz等)的任何請求都會觸發"ssl,authc"過濾器鏈"。 我們下面將描述過濾器鏈。

請注意,所有路徑表達式都與您的應用程序的根上下文相關。 這意味著如果您有一天將應用程序部署到www.somehost.com/myapp,然後又將其部署到www.anotherhost.com(沒有"myapp"子路徑),則模式匹配仍然可以工作。 所有路徑都與HttpServletRequest.getContextPath()值有關。

小心:順序問題

URL路徑表達式按照它們傳入請求的定義順序和「FIRST MATCH WINS」(首先匹配獲勝)進行鑒定。例如,讓我們假設有以下定義鏈:

如果傳入的請求打算到達/account/signup/index.html(可供所有"匿名"用戶訪問),它將永遠不會被處理!原因是/ account / **模式首先匹配傳入請求,並將所有剩餘定義"短路"。

永遠記得根據FIRST MATCH WINS策略定義您的過濾器鏈!

2) 過濾鏈定義

等號(=)右側的標記是用逗號分隔的過濾器列表,用於執行與該路徑匹配的請求。 它必須符合以下格式:

filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]

其中:

? filterN是[main]部分中定義的過濾器bean的名稱,並且

? [optional_configN] 是一個可選的括弧內的字元串,對那個特定路徑的特定過濾器有意義(每個過濾器,特定於路徑的配置!)。 如果過濾器不需要該URL路徑的特定配置,則可以放棄括弧,因此filterN[] 只會變成filterN。

並且因為過濾令牌定義了鏈(又名列表),請記住該順序很重要! 按照您希望請求流經的順序定義您的逗號分隔鏈列表。

最後,如果不滿足其必要條件(例如,執行重定向,用HTTP錯誤代碼響應,直接渲染等),每個過濾器都可以自由處理響應。 否則,按照預期,它會允許請求經由過濾鏈,到最終的目標視圖。

提示:

能夠對特定路徑的配置作出反應,即過濾器令牌的[optional_configN]部分,是Shiro過濾器可用的獨特功能。

3) 可用過濾器

可用於過濾器鏈定義的"過濾器"池在[main]部分定義。 在main部分分配給他們的名稱是過濾器鏈定義中使用的名稱。 例如:


運行Web應用程序時,Shiro將創建一些有用的默認過濾器實例,並自動在main部分使其可用。 您可以像在任何其他bean中一樣配置它們,並在鏈定義中引用它們。 例如:

可用的默認Filter實例自動由枚舉類DefaultFilter完成定義,枚舉的name欄位是可用於配置的名稱。 他們是:


與任何過濾器鏈定義機制(web.xml,Shiro的INI等)一樣,只需將過濾器包含在過濾器鏈定義中即可啟用該過濾器,並通過將其從鏈定義中刪除來禁用過濾器。

但Shiro 1.2中新增的一項新功能是可以啟用或禁用濾波器,而無需從濾波器鏈中刪除濾波器。 如果啟用(默認設置),則會按預期過濾請求。 如果禁用,則過濾器將允許請求立即通過FilterChain中的下一個元素。 通常可以基於配置屬性觸發過濾器的啟用狀態,或者甚至可以基於每個請求觸發它。

這是一個強大的概念,因為根據某些要求啟用或禁用過濾器通常比更改靜態過濾器鏈定義更方便,而靜態過濾器鏈定義是永久性且不靈活的。

Shiro通過它的OncePerRequestFilter抽象父類完成此操作。 所有Shiro的開箱即用濾波器實現都是這個子類的一個子類,因此可以在不從濾波器鏈中刪除它們的情況下啟用或禁用它們。 如果您也需要此功能,您可以將此類繼承為您自己的過濾器實現*。

*SHIRO-224(https://issues.apache.org/jira/browse/SHIRO-224)將有希望為任何過濾器啟用此功能,而不僅僅是那些子類OncePerRequestFilter。 如果這對你很重要,請為此問題投票。


OncePerRequestFilter(及其所有子類)支持跨所有請求啟用/禁用過濾器,與基於每個請求的一樣。

通常為所有請求啟用或禁用過濾器是通過將其enabled屬性設置為true或false來完成的。 默認設置為true,因為大多數濾波器在鏈中配置時是固化需要執行的。

例如,在shiro.ini中:

這個例子表明,很多URL路徑可能都需要一個請求必須通過SSL連接來保護。 在開發過程中設置SSL可能令人沮喪且費時。 在開發過程中,您可以禁用SSL過濾器。 部署到生產環境時,您可以使用一個配置屬性啟用它 - 這比手動更改所有URL路徑或維護兩個Shiro配置要容易得多。


OncePerRequestFilter根據isEnabled(request,response)方法實際確定是啟用還是禁用過濾器。

此方法默認返回enabled屬性的值,該屬性用於通常啟用/禁用上述所有請求。 如果您想根據請求特定條件啟用或禁用過濾器,則可以覆蓋OncePerRequestFilter.isEnabled(request,response)方法以執行更具體的檢查。


Shiro的PathMatchingFilter(OncePerRequestFilter的一個子類)可以根據被過濾的特定路徑對配置做出反應,這意味著除了傳入的請求和響應之外,還可以根據路徑和路徑特定的配置啟用或禁用過濾器。

如果您需要能夠響應匹配路徑和特定於路徑的配置以確定過濾器是啟用還是禁用,而不是重寫OncePerRequestFilter.isEnabled(request,response)方法,則可以覆蓋PathMatchingFilter.isEnabled(request,response ,path,pathConfig)方法。


在Web環境中,Shiro的默認會話管理器SessionManager的實現是ServletContainerSessionManager類。 這個非常簡單的實現將所有會話管理職責(包括會話群集,如果servlet容器支持它)委託給運行時Servlet容器。 它本質上是Shiro的會話API到servlet容器的橋樑,除此之外別無其他。

使用此默認值的好處是,應用與現有servlet容器的會話配置(超時、任何特定於容器的群集機制等)協同工作,且能按預期工作。

這個默認方式的缺點是把你綁定到servlet容器的特定會話行為。 例如,如果您想要群集會話,但是您使用Jetty進行測試並在生產中使用Tomcat,則您的容器特定配置(或代碼)將不可移植。

Servlet容器會話超時

如果使用默認的servlet容器支持,則可以在Web應用程序的web.xml文件中按預期配置會話超時。 例如:


如果您希望您的會話配置設置和集群可以跨servlet容器(例如,測試中的Jetty,生產中的Tomcat或JBoss)移植,或者您想要控制特定的會話/集群功能,則可以啟用Shiro的本地會話管理。

這裡"Native"一詞意味著Shiro自己的企業會話管理實現可用於支持所有Subject主體和HttpServletRequest會話,並完全繞過Servlet容器。 但是請放心 - Shiro直接實現了Servlet規範的相關部分,因此任何現有的Web/http相關代碼都能按預期工作,並且從不需要"知道"Shiro透明地管理著會話。

1)默認web會話管理器DefaultWebSessionManager

要為您的Web應用程序啟用本地會話管理,您需要配置一個支持Web的本地會話管理器來覆蓋默認的基於Servlet容器的會話管理器。 您可以通過在Shiro的SecurityManager上配置DefaultWebSessionManager的實例來實現這一點。 例如,在shiro.ini中:

shiro.ini 中本地web會話管理器配置代碼清單如下

本地會話管理器配置清單

一旦聲明,您可以使用會話超時和集群配置等本機會話選項配置DefaultWebSessionManager實例,如會話管理部分中所述。

2)本地會話超時

3)會話cookie

DefaultWebSessionManager支持兩種特定Web的配置屬性:

? sessionIdCookieEnabled(一個布爾值)

? sessionIdCookie,一個Cookie實例。

注意:模板cookie——sessionIdCookie屬性本質上是一個模板-您配置的Cookie實例屬性,那麼此模板將用於在運行時使用適當的會話ID值設置實際的HTTP"Cookie"頭。

4)會話cookie配置

DefaultWebSessionManager的sessionIdCookie默認實例是一個SimpleCookie。 這個簡單的實現,允許你希望在httpCookie上配置的所有相關屬性,以JavaBeans風格的屬性配置實現。

例如,您可以設置Cookie域:

有關其他屬性,請參閱SimpleCookie JavaDoc(http://shiro.apache.org/static/current/apidocs/org/apache/shiro/web/servlet/SimpleCookie.html)。

根據servlet規範,Cookie的默認名稱是JSESSIONID。 此外,Shiro的cookie支持HttpOnly標誌。 sessionIdCookie默認設置HttpOnly為true,以獲得額外的安全性。

注意:即使在Servlet 2.4和2.5環境中,Shiro的Cookie概念也支持HttpOnly標誌(而Servlet API中僅在2.6或更高版本才本地化支持該標誌屬性)。

5)禁用會話cookie

這個很簡單,如下代碼所示:


booleanisRememberMe();

如果此方法返回true,則Shiro將記住跨會話的終端用戶身份。

注意:UsernamePasswordTokenRememberMe

常用的UsernamePasswordToken已經實現了RememberMeAuthenticationToken介面並支持rememberMe登錄。


要以編程方式使用rememberMe,可以在支持此配置的類上將該值設置為true。 例如,使用標準的UsernamePasswordToken:


對於Web應用程序,authc過濾器默認為FormAuthenticationFilter。 這支持讀取"rememberMe"布爾值作為表單/請求參數。 默認情況下,它期望請求參數被命名為rememberMe。 下面是一個支持這個的shiro.ini配置示例:

然後,在你的網頁中,有一個名為"rememberMe"的複選框

默認情況下,FormAuthenticationFilter將查找名為username,password和rememberMe的請求參數。 如果這些與您在表單中使用的表單欄位名稱不同,則需要在FormAuthenticationFilter上配置名稱。 例如,在shiro.ini中:


您可以通過設置默認的RememberMeManager的各種cookie屬性來配置rememberMe cookie的功能。 例如,在shiro.ini中:

可以從JavaDOC上查看CookieRememberMeManager和支持SimpleCookie的配置屬性。


應該注意的是,如果默認的基於Cookie的RememberMeManager實現不能滿足您的需求,您可以插入任何您喜歡的安全管理器,如您配置任何其他對象引用一樣:


Apache Shiro提供了一個主體感知JSP/GSP標籤庫,允許您根據當前Subject的狀態來控制您的JSP、JSTL或GSP頁面輸出。 這對於基於身份標識和授權的當前用戶狀態的個性化頁面查詢非常有用。


標記庫描述符(TLD)文件捆綁在META-INF/shiro.tld文件的shiro-web.jar中。 要使用任何標籤,請將以下行添加到JSP頁面的頂部(或者您定義頁面指令的任何位置):

我們使用shiro前綴來表示shiro標籤庫名稱空間,但您可以指定您喜歡的任何名稱。

現在我們將覆蓋來討論每個標籤並展示它如何用於渲染頁面。

1- guest標籤

只有當前主體被視為"訪客"時,guest標記才會顯示其包裹的內容。 訪客是任何沒有身份的主體。 也就是說,我們不知道用戶是誰,因為他們沒有登錄,並且他們沒有從以前的網站訪問中被記住(從「記住我服務」中)。例如:

guest標籤與user標籤的邏輯是相反的。

2- user標籤

只有當前主體被認為是"用戶"時,用戶標籤才會顯示其包裝內容。 在這種情況下,"用戶"被定義為具有已知身份的主體,無論是來自成功認證還是來自"RememberMe"服務。 請注意,這個標籤在語義上與authenticated標籤不同,它比user標籤更具限制性。例如:

User標籤與guest標籤的邏輯是相反的。

3- Authenticated標籤

僅在當前用戶在當前會話期間成功通過身份驗證時才顯示正文內容。 它比"user"標籤更具限制性。 它在邏輯上與"notAuthenticated"標籤相反。

僅噹噹前主體已在當前會話期間成功通過身份驗證時,authenticated標記才會顯示其包裝內容。 這是比用戶更嚴格的標籤,用於保證敏感工作流中的身份。例如:

Authenticated標籤與notauthenticated標籤邏輯相反。

4- notAuthenticated標籤

如果當前主體尚未在當前會話中成功通過身份驗證,則notAuthenticated標記將顯示其包裝的內容。例如:

5- principal標籤

principal標籤將輸出主體的主題(識別屬性)或該主體的屬性。

沒有任何標籤屬性,標籤將渲染主題的toString()值。 例如(假設主題是一個字元串username),例如:

Hello,shiro:principal/>, how are you today?

幾乎相等的表達如下:

Hello,%=SecurityUtils.getSubject().getPrincipal().toString() %>, how are you today?

1)典型主題

principal標籤默認假設要列印的主題是subject.getPrincipal()值。 但是,如果您想列印一個不是主要主題的值,而是列印主體的主要集合中的另一個值,則可以按類型獲取該主體並列印該值。

例如,列印主體的用戶標識(而不是用戶名),假定標識在主體集合中:

User ID:principaltype="java.lang.Integer"/>

幾乎與下列語句的表達相等:

User ID:%=SecurityUtils.getSubject().getPrincipals().oneByType(Integer.class).toString() %>

2)主題屬性

但是如果主題(上面的默認主要主題或"類型"主題)是複雜的對象而不是簡單的字元串,您想如何引用該主題的某個屬性呢? 您可以使用property屬性來指示要讀取的屬性的名稱(必須可通過JavaBeans兼容的getter方法訪問)。 例如(假設主要的主體是一個用戶對象)

Hello,shiro:principalproperty="firstName"/>, how are you today?

上面的代碼,幾乎等同於下列的表達:

Hello,%=SecurityUtils.getSubject().getPrincipal().getFirstName().toString() %>, how are you today?

或者,結合type屬性的表達如下:

Hello,shiro:principaltype="com.foo.User"property="firstName"/>, how are you today?

這大致相當於以下內容:

Hello,%=SecurityUtils.getSubject().getPrincipals().oneByType(com.foo.User.class).getFirstName().toString() %>, how are you today?

6- hasRole標籤

只有噹噹前主體被分配了指定角色時,hasRole標籤才會顯示其包裝內容。例如:

hasRole標籤與lacksRole邏輯相反。

7- lacksRole標籤

僅噹噹前主體未被分配指定角色時,lacksRole標籤才會顯示其包裝內容。例如:

8- hasAnyRole標籤

如果當前主體被由逗號分隔的角色名稱列表中的任意指定角色分配,則hasAnyRole標籤將顯示其包裝內容。例如:

hasAnyRole標籤當前不具有邏輯上相反的標籤。

9- hasPermission標籤

hasPermission標籤只有在當前主體"具有"(暗含)指定許可權時才會顯示其包裝內容。 也就是說,用戶具有指定的能力。例如:

hasPermission標籤與lacksPermission標籤邏輯相反。

Ok,本篇關於Apache Shiro安全框架的web應用支持相關技術,就介紹到這裡。

最後,就請您關注一下本號,點個贊、收藏和分享一下吧。^_*


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 全球大搜羅 的精彩文章:

閑話 可愛冰塊
音樂隨筆,雕琢沉默

TAG:全球大搜羅 |