Spring Security 通過 http 元素下的子元素 session-management 提供了對 Http Session 管理的支持。
Spring Security 可以在用戶使用已經(jīng)超時的 sessionId 進行請求時將用戶引導(dǎo)到指定的頁面。這個可以通過如下配置來實現(xiàn)。
<security:http>
...
<!-- session 管理,invalid-session-url 指定使用已經(jīng)超時的 sessionId 進行請求需要重定向的頁面 -->
<security:session-management invalid-session-url="/session_timeout.jsp"/>
...
</security:http>
需要注意的是 session 超時的重定向頁面應(yīng)當(dāng)是不需要認(rèn)證的,否則再重定向到 session 超時頁面時會直接轉(zhuǎn)到用戶登錄頁面。此外如果你使用這種方式來檢測 session 超時,當(dāng)你退出了登錄,然后在沒有關(guān)閉瀏覽器的情況下又重新進行了登錄,Spring Security 可能會錯誤的報告 session 已經(jīng)超時。這是因為即使你已經(jīng)退出登錄了,但當(dāng)你設(shè)置 session 無效時,對應(yīng)保存 session 信息的 cookie 并沒有被清除,等下次請求時還是會使用之前的 sessionId 進行請求。解決辦法是顯示的定義用戶在退出登錄時刪除對應(yīng)的保存 session 信息的 cookie。
<security:http>
...
<!-- 退出登錄時刪除 session 對應(yīng)的 cookie -->
<security:logout delete-cookies="JSESSIONID"/>
...
</security:http>
此外,Spring Security 并不保證這對所有的 Servlet 容器都有效,到底在你的容器上有沒有效,需要你自己進行實驗。
通常情況下,在你的應(yīng)用中你可能只希望同一用戶在同時登錄多次時只能有一個是成功登入你的系統(tǒng)的,通常對應(yīng)的行為是后一次登錄將使前一次登錄失效,或者直接限制后一次登錄。Spring Security 的 session-management 為我們提供了這種限制。
首先需要我們在 web.xml 中定義如下監(jiān)聽器。
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
在 session-management 元素下有一個 concurrency-control 元素是用來限制同一用戶在應(yīng)用中同時允許存在的已經(jīng)通過認(rèn)證的 session 數(shù)量。這個值默認(rèn)是 1,可以通過 concurrency-control 元素的 max-sessions 屬性來指定。
<security:http auto-config="true">
...
<security:session-management>
<security:concurrency-control max-sessions="1"/>
</security:session-management>
...
</security:http>
當(dāng)同一用戶同時存在的已經(jīng)通過認(rèn)證的 session 數(shù)量超過了 max-sessions 所指定的值時,Spring Security 的默認(rèn)策略是將先前的設(shè)為無效。如果要限制用戶再次登錄可以設(shè)置 concurrency-control 的 error-if-maximum-exceeded 的值為 true。
<security:http auto-config="true">
...
<security:session-management>
<security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
</security:session-management>
...
</security:http>
設(shè)置 error-if-maximum-exceeded 為 true 后如果你之前已經(jīng)登錄了,然后想再次登錄,那么系統(tǒng)將會拒絕你的登錄,同時將重定向到由 form-login 指定的 authentication-failure-url。如果你的再次登錄是通過 Remember-Me 來完成的,那么將不會轉(zhuǎn)到 authentication-failure-url,而是返回未授權(quán)的錯誤碼 401 給客戶端,如果你還是想重定向一個指定的頁面,那么你可以通過 session-management 的 session-authentication-error-url 屬性來指定,同時需要指定該 url 為不受 Spring Security 管理,即通過 http 元素設(shè)置其 secure=”none”。
<security:http security="none" pattern="/none/**" />
<security:http>
<security:form-login/>
<security:logout/>
<security:intercept-url pattern="/**" access="ROLE_USER"/>
<!-- session-authentication-error-url 必須是不受 Spring Security 管理的 -->
<security:session-management session-authentication-error-url="/none/session_authentication_error.jsp">
<security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
</security:session-management>
<security:remember-me data-source-ref="dataSource"/>
</security:http>
在上述配置中我們配置了 session-authentication-error-url 為 “/none/session_authentication_error.jsp”,同時我們通過
在上述配置中為什么我們需要通過
此外,可以通過 expired-url 屬性指定當(dāng)用戶嘗試使用一個由于其再次登錄導(dǎo)致 session 超時的 session 時所要跳轉(zhuǎn)的頁面。同時需要注意設(shè)置該 URL 為不需要進行認(rèn)證。
<security:http auto-config="true">
<security:form-login/>
<security:logout/>
<security:intercept-url pattern="/expired.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<security:intercept-url pattern="/**" access="ROLE_USER"/>
<security:session-management>
<security:concurrency-control max-sessions="1" expired-url="/expired.jsp" />
</security:session-management>
</security:http>
session 固定是指服務(wù)器在給客戶端創(chuàng)建 session 后,在該 session 過期之前,它們都將通過該 session 進行通信。session 固定攻擊是指惡意攻擊者先通過訪問應(yīng)用來創(chuàng)建一個 session,然后再讓其他用戶使用相同的 session 進行登錄(比如通過發(fā)送一個包含該 sessionId 參數(shù)的鏈接),待其他用戶成功登錄后,攻擊者利用原來的 sessionId 訪問系統(tǒng)將和原用戶獲得同樣的權(quán)限。Spring Security 默認(rèn)是對 session 固定攻擊采取了保護措施的,它會在用戶登錄的時候重新為其生成一個新的 session。如果你的應(yīng)用不需要這種保護或者該保護措施與你的某些需求相沖突,你可以通過 session-management 的 session-fixation-protection 屬性來改變其保護策略。該屬性的可選值有如下三個。