Apache Shiro 的Web支持
配置
將Shiro集成到web項(xiàng)目中最簡單的方式就是在web.xml中配置一個(gè)Servlet的ContextListener和過濾器,讓W(xué)eb項(xiàng)目知道如何讀取Shiro的INI配置文件。關(guān)于INI配置文件的內(nèi)容,在前面有描述,這里將會(huì)講述一些Web相關(guān)的小節(jié)
如果使用了
Spring框架,將不需要考慮這一步,詳情請(qǐng)看Spring集成Shiro的相關(guān)文檔
web.xml
Shiro1.2及以后
在Shiro1.2及之后的版本中,標(biāo)準(zhǔn)的Web應(yīng)用程序集成Shiro,就是將下列的xml內(nèi)容添加到web.xml中:
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
...
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
如果沒有顯式配置INI配置文件的位置,Shiro將會(huì)按照下面的順序找配置文件,使用第一個(gè)找到的配置文件:
/WEB-INF/shiro.ini類路徑的根路徑下的shiro.ini
以上的配置其實(shí)是做了以下的事:
-
EnvironmentLoaderListener會(huì)初始化一個(gè)Shiro的WebEnvironment實(shí)例(該實(shí)例包含了Shiro需要的所有東西,包括SecurityManager),并將這個(gè)實(shí)例設(shè)置到了ServletContext中使其可用。如果需要獲取這個(gè)WebEnvironment實(shí)例,可以通過WebUtils.getRequiredWebEnvironment(servletContext)獲得 -
ShiroFilter將會(huì)通過WebEnvironment來執(zhí)行所有的安全相關(guān)操作 - 最后,
filter-mapping定義確保了所有的請(qǐng)求都能經(jīng)過ShiroFilter的過濾
通常需要把
ShiroFilter的filter-mapping定義在所有的filter-mapping之前,確保Shiro也能作用在其他過濾器之中
ShiroFilter是一個(gè)標(biāo)準(zhǔn)的servlet過濾器,它的默認(rèn)編碼是ISO-8859-1,然而客戶端可以通過使用請(qǐng)求頭的Content-Type頭部的charset屬性來指定編碼
自定義 WebEnvironment 類
EnvironmentLoaderListener將默認(rèn)創(chuàng)建的是IniWebEnvironment實(shí)例,顧名思義是通過INI配置Shiro。如果有需要,可以在web.xml中為ServletContext指定一個(gè)context-param參數(shù),來指定WebEnvironment
<context-param>
<param-name>shiroEnvironmentClass</param-name>
<param-value>com.foo.bar.shiro.MyWebEnvironment</param-value>
</context-param>
這種方式可以讓我們自定義Shiro配置的格式,并將其解析為一個(gè)WebEnvironment實(shí)例,可以繼承IniWebEnvironment來繼續(xù)使用ini的配置格式,或者完全自定義配置格式
配置文件路徑
IniWebEnvironment類需要讀取INI配置文件才能配置Shiro,默認(rèn)情況下,這個(gè)類將會(huì)自動(dòng)的從以下兩個(gè)位置順序的尋找配置文件,只要找到了配置文件就會(huì)使用它(如果同時(shí)在兩個(gè)位置都有配置文件,則會(huì)使用第一個(gè)/WEB-INF/shiro.ini)
/WEB-INF/shiro.iniclasspath:shiro.ini
可以在web.xml中配置一個(gè)context-param來指定配置文件的位置
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>YOUR_RESOURCE_LOCATION_HERE</param-value>
</context-param>
默認(rèn)情況下,這個(gè)參數(shù)值會(huì)按照ServletContext.getResource()方法來解析,如"/WEB-INF/some/path/shiro.ini"。Shiro的ResourceUtils類也支持"url:","file:"這樣的資源路徑前綴來指定路徑,下面的路徑也是可以使用的
file:/home/foobar/myapp/shiro.iniclasspath:com/foo/bar/shiro.iniurl:http://confighost.mycompany.com/myapp/shiro.ini
Shiro1.1及之前
Web應(yīng)用集成Shiro1.1及之前版本,最簡單的就是定義IniShiroFilter及其相關(guān)filter-mapping
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class>
</filter>
...
<!-- Make sure any request you want accessible to Shiro is filtered. /* catches all -->
<!-- requests. Usually this filter mapping is defined first (before all others) to -->
<!-- ensure that Shiro works in subsequent filters in the filter chain: -->
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
以上定義要求INI配置,且INI配置文件在類路徑的根路徑下,即classpath:shiro.ini。注意這里放在/WEB-INF/下面無效
配置文件路徑
如果不想讓INI配置文件放在classpath:shiro.ini,也可以指定一個(gè)資源文件路徑。需要為ShiroFilter添加一個(gè)configPath參數(shù)
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class>
<init-param>
<param-name>configPath</param-name>
<param-value>classpath:anotherFile.ini</param-value>
</init-param>
</filter>
...
請(qǐng)注意,ServletContext 資源路徑是在Shiro1.2及之后可用的,在1.1及之前的版本中,所有的configPath定義都需要指定classpath:,file:或者url:前綴,也就是說,這里不能寫/WEB-INF/shiro.ini,就算寫了也會(huì)沒有效果。官網(wǎng)寫的有點(diǎn)模糊,試了下,應(yīng)該是這樣
在web.xml文件中嵌入Shiro配置
可以使用名為config的init-param的參數(shù)設(shè)置,將INI配置嵌入到web.xml中,這樣就不需要使用額外的ini配置文件了
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class>
<init-param><param-name>config</param-name><param-value>
# INI Config Here
</param-value></init-param>
</filter>
...
這種配置方式比較適用于小的,簡單的應(yīng)用,但出于以下原因,將其放到專門的shiro.ini文件中通常更為方便:
- 你可能會(huì)頻繁修改安全的配置,這會(huì)為
web.xml增加一個(gè)版本控制噪聲 - 你可能想要將安全相關(guān)的配置從
web.xml中分離出來 - 你可能需要寫很多
Shiro的相關(guān)配置,如果寫了太多,反而會(huì)讓web.xml文件過于臃腫 - 相同的
Shiro配置需要用在多個(gè)部分時(shí)
Web相關(guān)的INI配置項(xiàng)
[main],[users],[roles]小節(jié)前面已經(jīng)講述過了,這里重點(diǎn)介紹Web項(xiàng)目特有的[urls]小節(jié)
# [main], [users] and [roles] above here
...
[urls]
...
[urls]小節(jié)允許你為你的應(yīng)用程序中任何匹配的URL路徑定義專門的過濾器鏈的能力,這比在web.xml中定義過濾器鏈的方式更加靈活、強(qiáng)大和簡潔,即使只使用這個(gè)特性,它也值得一用
[urls]
URL路徑表達(dá)式
[urls] 小節(jié)的每一行遵從以下格式:
_URL_Ant_Path_Expression_ = _Path_Specific_Filter_Chain_
例如:
...
[urls]
/index.html = anon
/user/create = anon
/user/** = authc
/admin/** = authc, roles[administrator]
/rest/** = authc, rest
/remoting/rpc/** = authc, perms["remote:invoke"]
等號(hào)左邊的是一個(gè)Ant風(fēng)格的路徑表達(dá)式,注意,所有的路徑表達(dá)式都是從應(yīng)用程序環(huán)境中的根目錄開始匹配的,也就是說,如果你的部署從www.somehost.com/myapp換成了www.anotherhost.com,配置不需要更改,依然有效。所有的路徑都是相對(duì)于HttpServletRequest.getContextPath()的值
到來的請(qǐng)求會(huì)按照
urls定義的順序來匹配,第一個(gè)匹配的配置項(xiàng)則為該路徑需要通過的過濾器鏈。假如有如下配置/account/** = ssl, authc /account/signup = anon則請(qǐng)求路徑
/account/signup將永遠(yuǎn)不會(huì)被正確的處理(匿名可訪問),應(yīng)為第一條配置項(xiàng)/account/**已經(jīng)匹配了這個(gè)請(qǐng)求,后面的就沒用了
過濾器鏈定義
等號(hào)右邊就是以逗號(hào)風(fēng)格的過濾器鏈,它的格式如下
filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]
-
filterN是Filter在[main]小節(jié)中定義的名字 -
[optional_config]是一個(gè)帶括號(hào)的可選字符串,它只對(duì)部分路徑的部分過濾器有意義,如果過濾器不需要這個(gè)特定的配置,可以放棄方括號(hào),這樣filter[]就變成了filter
請(qǐng)求通過過濾鏈的順序就是它們?cè)谂渲梦募卸x的順序。
響應(yīng)也會(huì)通過這個(gè)過濾器鏈,如果沒有滿足必要條件(例如執(zhí)行重定向、響應(yīng)帶有HTTP錯(cuò)誤代碼、直接呈現(xiàn)等),每個(gè)過濾器都可以自由地處理響應(yīng)。否則,它將允許請(qǐng)求繼續(xù)通過鏈到達(dá)最終目標(biāo)視圖
通過
[optional_configN]能夠?qū)μ囟窂脚渲米龀龇磻?yīng),這是Shiro的獨(dú)特特性,如果你想要?jiǎng)?chuàng)建一個(gè)能做到這些功能的javax.servlet.Filter實(shí)現(xiàn),需要確保其繼承了org.apache.shiro.web.filter.PathMatchingFilter
可用的過濾器
在[main]小節(jié)中可以定義需要使用的過濾器,其中定義的名字就是在過濾器鏈的定義中需要使用的名字,如下所示
[main]
...
myFilter = com.company.web.some.FilterImplementation
myFilter.property1 = value1
...
[urls]
...
/some/path/** = myFilter
默認(rèn)過濾器
當(dāng)運(yùn)行一個(gè)web應(yīng)用的時(shí)候,Shiro默認(rèn)會(huì)創(chuàng)建一些有用的過濾器實(shí)例,我們可以在[main]小節(jié)中直接使用這些實(shí)例,也可以在[main]小節(jié)中對(duì)它們進(jìn)行配置,就和其他定義的bean一樣
[main]
...
# 我們并沒有定義FormAuthenticationFilter ('authc'),這是Shiro自動(dòng)定義好的
authc.loginUrl = /login.jsp
...
[urls]
...
# 如果用戶沒有經(jīng)過認(rèn)證,則防止這個(gè)URL時(shí)將會(huì)重定向到authc.loginUrl配置的路徑,之后如果用戶通過了認(rèn)證,則將會(huì)回到原來的頁面
/account/** = authc
...
以下是Shiro自動(dòng)定義好的過濾器及其在main中可用的名字
| 名字 | 類 |
|---|---|
| anno | org.apache.shiro.web.filter.authc.AnonymousFilter |
| authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
| authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
| authcBearer | org.apache.shiro.web.filter.authc.BearerHttpAuthenticationFilter |
| invalidRequest | org.apache.shiro.web.filter.InvalidRequestFilter |
| logout | org.apache.shiro.web.filter.authc.LogoutFilter |
| noSessionCreation | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
| 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.zuthc.UserFilter |
開啟和關(guān)閉過濾器
在過濾器鏈中開啟或關(guān)閉一個(gè)過濾器最直接的方式,就是通過將其從過濾器鏈定義中添加或刪除其名字。但是在Shiro1.2之后新增加了一個(gè)特性,可以不用通過前面那種方式就能開啟或關(guān)閉過濾器,可以通過一個(gè)配置的屬性來判斷是否開啟過濾器,甚至也可以通過每一個(gè)請(qǐng)求來判斷
Shiro提供了一個(gè)OncePerRequestFilter的抽象類,所有的繼承它的過濾器都可以在不將其從過濾器鏈中刪除的情況下控制其是否生效,我們也可以繼承這個(gè)類來實(shí)現(xiàn)這個(gè)功能
一般的開啟和關(guān)閉
OncePerRequestFilter的開關(guān)可以對(duì)所有的請(qǐng)求生效,也可以對(duì)基于某一個(gè)請(qǐng)求生效。設(shè)置enabled屬性為true或false就可以設(shè)置它的開關(guān),該屬性的默認(rèn)值為true,因此大多數(shù)過濾器都是開啟狀態(tài)的
[main]
...
# 配置ssl過濾器失效
ssl.enabled = false
[urls]
...
/some/path = ssl, authc
/another/path = ssl, roles[admin]
...
絕大多數(shù)情況下,URL都是配置了SSL的,如果在開發(fā)時(shí)還開啟了SSL,那是很難受的,所以可以先將其關(guān)閉,在生產(chǎn)環(huán)境下再把它開起來
根據(jù)請(qǐng)求
OncePerRequestFilter還可以通過它的isEnable(request, response) 方法來對(duì)每一個(gè)請(qǐng)求進(jìn)行檢查,判斷是否需要經(jīng)過該過濾器過濾。該方法的默認(rèn)實(shí)現(xiàn)是直接返回enable屬性,也就是說,本質(zhì)上OncePerRequestFilter就是通過isEnable方法來判斷是否開啟該過濾器的。我們可以通過重寫這個(gè)isEnable(request, response)來進(jìn)行更細(xì)致的檢查
根據(jù)路徑
Shiro的PathMatchingFilter(OncePerRequestFilter的子類)擁有對(duì)特定路徑的請(qǐng)求進(jìn)行過濾的能力,也就是說,可以對(duì)一個(gè)請(qǐng)求的路徑來判斷是否開啟過濾器。如果你的過濾器需要這種能力,則可以重寫PathMatchingFilter的isEnabled(request, response, path, pathConfig)方法
全局過濾器
從Shiro1.6開始,可以定義一個(gè)一條全局過濾器鏈,它將會(huì)作用于所有的路由,包括哪些沒有配置過濾器鏈的路由。默認(rèn)情況下,這個(gè)全局過濾器鏈包含了invalidRequest過濾器(上面的表格中有),這個(gè)過濾器是負(fù)責(zé)過濾掉無效請(qǐng)求的,可以阻擋一些惡意攻擊
全局過濾器鏈的配置和關(guān)閉如下
[main]
...
# 關(guān)閉全局過濾器鏈
filterChainResolver.globalFilters = null
定義一條全局過濾器鏈
[main]
...
filterChainResolver.globalFilters = invalidRequest, port
invalidRequest過濾器會(huì)阻塞使用非ascii字符、分號(hào)和反斜杠的請(qǐng)求,可以單獨(dú)禁用其中的每一個(gè),以便于向后兼容
[main]
...
invalidRequest.blockBackslash = true
invalidRequest.blockSemicolon = true
invalidRequest.blockNonAscii = true
...
如果你的應(yīng)用程序允許在
URL中重寫jsessionid,那么必須將blockSemicolon設(shè)置為false
HSTS
SslFilter及其所有的子類,支持HSTS的概念,我們可以開啟或關(guān)閉HSTS
[main]
...
# 配置ssl過濾器開啟HSTS
ssl.enabled = true
ssl.hsts.enabled = true
ssl.hsts.includeSubDomains = true
[urls]
...
/some/path = ssl, authc
/another/path = ssl, roles[admin]
...
會(huì)話管理
Servlet容器會(huì)話
在Web環(huán)境下,Shiro的默認(rèn)會(huì)話管理器是ServletContainerSessionManager,Shiro會(huì)把所有的會(huì)話管理都委托給Servlet容器(包括會(huì)話集群,如果Servlet容器支持的話)。這是一個(gè)Shiro的SessionAPI與Servlet容器的橋梁
這種方式的好處就是,應(yīng)用程序可以使用Servlet容器的配置,如會(huì)話超時(shí),容器的集群設(shè)置等等。缺點(diǎn)就是應(yīng)用程序和Servlet容器綁定了,比如如果開發(fā)環(huán)境使用的是Jetty,生產(chǎn)環(huán)境使用Tomcat,那么一些特定于容器的配置將會(huì)需要更改
Servlet容器會(huì)話的超時(shí)時(shí)間
如果使用Servlet容器來管理會(huì)話的話,則可以在web.xml中配置會(huì)話超時(shí)時(shí)間
<session-config>
<!-- 配置會(huì)話超時(shí)時(shí)間為30分鐘 -->
<session-timeout>30</session-timeout>
</session-config>
原生會(huì)話
如果想要會(huì)話的配置能夠跨Servlet容器生效的話,應(yīng)該使用Shiro的原生會(huì)話管理?!霸币馕吨褂肧hiro自己的企業(yè)會(huì)話管理,這樣可以完全地支持Subject和HttpServletRequest會(huì)話,完全繞過Servlet容器。請(qǐng)放心,Shiro直接實(shí)現(xiàn)了Servlet規(guī)范的相關(guān)部分,因此任何現(xiàn)有的Web/HTTP相關(guān)代碼都可以按預(yù)期工作,對(duì)于它們來說,Shiro是透明的
DefaultWebSessionManager
在web應(yīng)用中開啟Shiro的原生會(huì)話管理,只需要為SecurityManager配置一個(gè)DefaultWebSessionManager實(shí)例即可,如下
[main]
...
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
# 如果需要的話,在這里配置屬性
# 使用配置好的原生會(huì)話管理器
securityManager.sessionManager = $sessionManager
可以為DefaultWebSessionManager實(shí)例配置所有原生會(huì)話的配置選項(xiàng),如超時(shí)時(shí)間和集群配置等
原生會(huì)話的超時(shí)時(shí)間
在配置了DefaultWebSessionManager實(shí)例后,可以像前面介紹會(huì)話管理那樣設(shè)置會(huì)話超時(shí)時(shí)間
會(huì)話Cookie
DefaultWebSessionManager有兩個(gè)Web相關(guān)的配置屬性:
-
sessionIdCookieEnabled——一個(gè)布爾屬性 -
sessionIdCookie,一個(gè)Cookie實(shí)例
sessionIdCookie屬性是一個(gè)Cookie實(shí)例,它作為一個(gè)模板,這個(gè)模板會(huì)被用來在運(yùn)行時(shí)使用適當(dāng)?shù)臅?huì)話ID值設(shè)置實(shí)際的HTTP ‘Cookie'頭。
會(huì)話Cookie配置
DefaultWebSessionManager的sessionIdCookie的默認(rèn)是一個(gè)SimpleCookie實(shí)例,它是一個(gè)JavaBean的形式來設(shè)置相關(guān)屬性值
[main]
...
securityManager.sessionManager.sessionIdCookie.domain = foo.com
查看SimpleCookie的Java文檔查看更多信息
根據(jù)Servlet規(guī)范,cookie的默認(rèn)名是JSESSIONID,Shiro還支持HttpOnly和SameSite標(biāo)識(shí),為了安全性,sessionIdCookie默認(rèn)將會(huì)設(shè)置HttpOnly為true,設(shè)置SameSite為LAX
關(guān)閉會(huì)話的Cookie
如果不想使用會(huì)話Cookie,可以通過sessionIdCookieEnabled屬性值,將其設(shè)置為false
[main]
...
securityManager.sessionManager.sessionidCookieEnabled = false
“記住我”功能
如果AuthenticationToken實(shí)現(xiàn)了org.apache.shiro.authc.RememberMeAuthenticationToken接口,那Shiro將會(huì)根據(jù)接口的方法來判斷是否提供”記住我“服務(wù)
boolean isRememberMe();
如果這個(gè)方法返回true,那Shiro將會(huì)跨會(huì)話的記住終端用戶的標(biāo)識(shí)
UsernamePasswordToken和 記住我最常用的
UsernamePasswordToken已經(jīng)實(shí)現(xiàn)了RememberMeAuthenticationToken接口,支持”記住我“服務(wù)
編程式配置
可以通過將登陸時(shí)使用的RememberMeAuthenticationToken或其子類的rememberMe屬性值設(shè)置為true來開啟”記住我“服務(wù),如下
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);
SecurityUtils.getSubject().login(token);
...
基于表單的登錄
在Web應(yīng)用程序中,authc過濾器默認(rèn)是一個(gè)FormAuthenticationFilter,它能夠讀取請(qǐng)求參數(shù)中的rememberMe參數(shù),默認(rèn)情況下參數(shù)名就是rememberMe
[main]
authc.loginUrl = /login.jsp
[urls]
# 登陸頁面
login.jsp = authc
# 這樣設(shè)置真的不會(huì)陷入死循環(huán)嗎?
在你的Web表單中,添加一個(gè)名為rememberMe的checkbox
<form ...>
Username: <input type="text" name="username"/> <br/>
Password: <input type="password" name="password" />
...
<input type="checkbox" name="rememberMe" value="true"/> Remember Me?
...
</form>
默認(rèn)情況下,FormAuthenticationFilter將會(huì)尋找名為username,password和rememberMe的請(qǐng)求參數(shù),可以配置FormAuthenticationFilter來自定義參數(shù)名字
[main]
...
authc.loginUrl=/whatever.jsp
authc.usernameParam=somethingOtherThanUsername
authc.passwordParam=somethingOtherThanPassword
authc.rememberMeParam=somethingOtherThanRememberMe
...
Cookie配置
還可以設(shè)置rememberMe的cookie如何生效
[main]
...
securityManager.rememberMeManager.cookie.name = foo
securityManager.rememberMeManager.cookie.maxAge = blah
...
詳情可以看CookieRememberMemanager和SimpleCookie的JavaDoc
自定義RememberMeManager
如果默認(rèn)的RememberMeManager實(shí)現(xiàn)不能滿足你的需求,也可以自定義
[main]
...
rememberMeManager = com.my.impl.RememberMeManager
securityManager.rememberMeManager = $rememberMeManager
...
JSP/GSP標(biāo)簽庫
Apache Shiro提供了一個(gè)Subject可以感知的JSP/GSP標(biāo)記庫,允許根據(jù)當(dāng)前Subject狀態(tài)控制JSP,JSTL或GSP頁面輸出。 對(duì)于基于當(dāng)前用戶查看網(wǎng)頁的特定用戶的身份和授權(quán)狀態(tài),這對(duì)于個(gè)性化視圖非常有用
標(biāo)簽庫配置
JSP/GSP的標(biāo)簽庫描述文件(TLD)是在shiro-web.jar中的META-INF/shiro.tld的,在JSP頁面中添加下面這一行來使用標(biāo)簽
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
我們將會(huì)使用shiro前綴最為Shiro標(biāo)簽庫的命名空間,當(dāng)然可以使用自己喜歡的前綴
下面來介紹一些標(biāo)簽
guest
guest包裹的內(nèi)容,只會(huì)展示給那些未登錄的用戶
<shiro:guest>
這里是未登錄的游客才能看到的東西
</shiro:guest>
guest標(biāo)簽的對(duì)立面即為user標(biāo)簽
user
與guest相反,user標(biāo)簽包裹的內(nèi)容只會(huì)展示給那些登錄的用戶,其中包括在之前的會(huì)話中被記住的用戶,注意這個(gè)標(biāo)簽和authenticated標(biāo)簽是不一樣的,后者更為嚴(yán)格
<shiro:user>
這里是展示給登錄的用戶的
</shiro:user>
該標(biāo)簽和guest標(biāo)簽相反
authenticated
只有當(dāng)前Subject是已認(rèn)證的,才會(huì)展示該標(biāo)簽包裹的內(nèi)容。注意它和user標(biāo)簽的區(qū)別,具體參考之前描述的已認(rèn)證和已記住兩個(gè)狀態(tài)
<shiro:authenticated>
這里是已認(rèn)證的用戶才能看到的
</shiro:authenticated>
該標(biāo)簽和notAuthenticated是相反的
notAuthenticated
該標(biāo)簽包裹的內(nèi)容只會(huì)展示給那些未認(rèn)證的Subject
<shiro:notAuthenticated>
這里是未認(rèn)證的用戶才能看到的
</shiro:notAuthenticated>
該標(biāo)簽和authenticated相反
principal
principal 標(biāo)簽將會(huì)輸出Subject的principal信息(即用戶的身份信息)或者其屬性。如果沒有指定輸出哪個(gè)標(biāo)簽屬性,該標(biāo)簽將會(huì)輸出principal的toString()方法,如
<shiro:principal/>
和下面的輸出結(jié)果是一樣的
<%= SecurityUtils.getSubject().getPrincipal().toString() %>
根據(jù)類型選擇principal
principal標(biāo)簽?zāi)J(rèn)是輸出subject.getPrincipal()值,如果想要輸出的不是primary principal,而是Subject的其他principal,可以通過principal的類型來選擇輸出
<principal type="java.lang.Integer" />
上面的標(biāo)簽和下面的輸出是一樣的
<%= SecurityUtils.getSubject().getPrincipals().oneByType(Integer.class).toString() %>
Principal的屬性
如果principal是一個(gè)復(fù)雜類型的數(shù)據(jù),而不是一個(gè)簡單的字符串,我們還可以通過property屬性來指定輸出principal的哪個(gè)屬性值
<shiro:principal property="firstName" />
下面是它的等效結(jié)果
<%= SecurityUtils.getSubject().getPrincipal().getFirstName().toString() %>
還可以結(jié)合Principal的類型進(jìn)行輸出
<shiro:principal type="com.foo.User" property="firstname"/>
它和下面的輸出是一樣的
<%= SecurityUtils.getSubject().getPrincipals().oneByType(com.foo.User.class).getFirstName().toString() %>
hasRole
該標(biāo)簽包裹的內(nèi)容只會(huì)展示給具有特定角色的用戶
<shiro:hasRole name="administrator">
只有擁有administrator角色的用戶才能看到
</shiro:hasRole>
該標(biāo)簽和lacksRole標(biāo)簽相反
lacksRole
該標(biāo)簽包裹的內(nèi)容只會(huì)展示給不具有特定角色的用戶
<shiro:lacksRole name="administrator">
只有沒有administrator角色的用戶才能看到
</shiro:lacksRole>
該標(biāo)簽與hasRole標(biāo)簽相反
hasAnyRole
該標(biāo)簽包裹的內(nèi)容,只有那些具有指定角色集合的其中一個(gè)角色才能看到
<shiro:hasAnyRoles name="developer, project manager, administrator" >
需要具有developer,project manager,administrator至少一個(gè)角色的用戶的才能看到
</shiro:hasAnyRoles>
該標(biāo)簽沒有邏輯上相反的標(biāo)簽
hasPermission
參考hasRole
<shiro:hasPermission name="user:create">
內(nèi)容
</shiro:hasPermission>
lacksPermission
參考lacksRole
<shiro:lacksPermission name="user:delete">
內(nèi)容
</shiro:lacksPermission>