最新版Apache Shiro 的Web應用支持指南

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

1. 配置

將Shiro集成到任何Web應用程序中的最簡單方法是在web.xml中配置Servlet ContextListener和Filter,它們瞭解如何讀取Shiro的INI配置。 大部分的INI配置格式本身是在配置頁面的INI部分中定義的,但我們將在這裡介紹一些其他特定於網絡的部分。

提示:Spring Framework用戶不要執行此配置。 如果你使用Spring,我們另行講解特定於Spring的web配置。

1.1 web.xml文件配置

1. Shiro1.2及更高版

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

最新版Apache Shiro 的Web應用支持指南

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配置

定製WebEnvironment

類?

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

最新版Apache Shiro 的Web應用支持指南

自定義WebEnvironment

這使您可以自主定義配置格式並將其解析為WebEnvironment實例。 您可以將現有的IniWebEnvironment子類化,實現自定義行為,或完全支持不同的配置格式。 例如,如果有人想用XML而不是INI配置Shiro,他們可以創建一個基於XML的實現,例如, com.foo.bar.shiro.XmlWebEnvironment。

定製配置文件位置

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

1) /WEB-INF/shiro.ini

2) classpath:shiro.ini

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

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

最新版Apache Shiro 的Web應用支持指南

自定義配置文件位置

默認情況下,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並指定過濾器映射:

最新版Apache Shiro 的Web應用支持指南

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

定製路徑

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

最新版Apache Shiro 的Web應用支持指南

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

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

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

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

最新版Apache Shiro 的Web應用支持指南

內聯配置

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

最新版Apache Shiro 的Web應用支持指南

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

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

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

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

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

1.2 Web INI配置

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

最新版Apache Shiro 的Web應用支持指南

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

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

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

1) [urls]

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

_URL_Ant_Path_Expression_ = _Path_Specific_Filter_Chain_

示例如下:

最新版Apache Shiro 的Web應用支持指南

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

等號(=)左側的標記是相對於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”(首先匹配獲勝)進行鑑定。 例如,讓我們假設有以下定義鏈:

最新版Apache Shiro 的Web應用支持指南

如果傳入的請求打算到達/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過濾器可用的獨特功能。

如果你想創建自己的javax.servlet.Filter實現,也可以這樣做,確保你的過濾器為org.apache.shiro.web.filter.PathMatchingFilter的子類。

3) 可用過濾器

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

最新版Apache Shiro 的Web應用支持指南

2. 默認過濾器

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

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

最新版Apache Shiro 的Web應用支持指南

3. 啟用禁止過濾器

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

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

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

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

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

3.1 通用啟用/禁用

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

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

例如,在shiro.ini中:

最新版Apache Shiro 的Web應用支持指南

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

3.2 特殊請求的啟用和禁用

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

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

3.3 特殊路徑的啟用和禁用

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

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

4. 會話管理

4.1 Servlet容器會話

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

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

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

Servlet容器會話超時

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

最新版Apache Shiro 的Web應用支持指南

4.2 本地會話

如果您希望您的會話配置設置和集群可以跨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會話管理器配置代碼清單如下):

最新版Apache Shiro 的Web應用支持指南

本地會話管理器配置清單

2)本地會話超時

在配置DefaultWebSessionManager實例後,會話超時配置如“會話管理:會話超時”(http://shiro.apache.org/session-management.html#SessionManagement-sessionTimeout)部分所述一樣(將另行講解)。

3)會話cookie

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

• sessionIdCookieEnabled(一個布爾值)

• sessionIdCookie,一個Cookie實例。

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

4)會話cookie配置

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

例如,您可以設置Cookie域:

最新版Apache Shiro 的Web應用支持指南

有關其他屬性,請參閱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

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

最新版Apache Shiro 的Web應用支持指南

5. “記住我”服務

如果AuthenticationToken實現org.apache.shiro.authc.RememberMeAuthenticationToken接口,Shiro將執行'rememberMe'服務。 該接口指定一個方法:

booleanisRememberMe

();

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

注意:UsernamePasswordTokenRememberMe

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

5.1編程式支持

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

最新版Apache Shiro 的Web應用支持指南

5.2 基於表單登錄

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

最新版Apache Shiro 的Web應用支持指南

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

最新版Apache Shiro 的Web應用支持指南

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

最新版Apache Shiro 的Web應用支持指南

5.3 Cookie配置

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

最新版Apache Shiro 的Web應用支持指南

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

5.4 定製RememberMeManager

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

最新版Apache Shiro 的Web應用支持指南

6. Shiro標籤庫(JSP/GSP標籤庫)

6.1 標籤庫配置

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

%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

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

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

1- guest標籤

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

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

2- user標籤

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

最新版Apache Shiro 的Web應用支持指南

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

3- Authenticated標籤

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

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

最新版Apache Shiro 的Web應用支持指南

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標籤才會顯示其包裝內容。例如:

最新版Apache Shiro 的Web應用支持指南

hasRole標籤與lacksRole邏輯相反。

7- lacksRole標籤

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

最新版Apache Shiro 的Web應用支持指南

8- hasAnyRole標籤

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

最新版Apache Shiro 的Web應用支持指南

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

9- hasPermission標籤

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

最新版Apache Shiro 的Web應用支持指南

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

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

原文地址:

http://mp.weixin.qq.com/s?__biz=MzIzNzk2OTQ1OQ==&mid=100000038&idx=1&sn=249284d3f5377aa912edb1f64730d0b3&chksm=68c1c87a5fb6416c35d1d787ee0a8c051568121cf3b54d7d4644f5be8ba0c5b5bc22c8c7234b#rd

最新版Apache Shiro 的Web應用支持指南


分享到:


相關文章: