在本文中,咱們將說明Spring Security如何容許咱們控制HTTP會話。此控件的範圍從會話超時到啓用併發會話和其餘高級安全配置。html
咱們能夠準確控制會話什麼時候建立以及Spring Security如何與之交互:git
<http create-session="ifRequired">...</http>
@Override protected void configure(HttpSecurity http) throws Exception { http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) }
了解此配置僅控制Spring Security的功能很是重要 - 而不是整個應用程序。若是咱們不指示Spring Security,可能沒法建立會話,但咱們的應用程序可能會!github
默認狀況下,Spring Security會在須要時建立會話 - 這是「ifRequired」。web
對於更無狀態的應用程序,「never」選項將確保Spring Security自己不會建立任何會話;可是,若是應用程序建立了一個,那麼Spring Security將使用它。spring
最後,最嚴格的會話建立選項 - 「stateless」 - 保證應用程序根本不會建立任何會話。編程
這是在Spring 3.1中引入的,它將有效地跳過部分Spring Security過濾器鏈。主要是會話相關的部分,如HttpSessionSecurityContextRepository,SessionManagementFilter,RequestCacheFilter。瀏覽器
這些更嚴格的控制機制直接暗示不使用cookie,因此每一個請求都須要從新進行身份驗證。這種無狀態架構適用於REST API及其無狀態約束。它們也適用於基本和摘要式身份驗證等身份驗證機制。安全
在執行身份驗證過程以前,Spring Security將運行一個負責在請求之間存儲安全上下文的過濾器-SecurityContextPersistenceFilter。上下文將根據策略存儲 - 默認狀況下爲HttpSessionSecurityContextRepository - 它使用HTTP會話做爲存儲。對於strict create-session =「stateless」屬性,此策略將替換爲另外一個 - NullSecurityContextRepository - 而且不會建立或使用會話來保留上下文。cookie
當已通過身份驗證的用戶嘗試再次進行身份驗證時,應用程序能夠經過如下幾種方式之一處理該事件。它可使用戶的活動會話無效,並使用新會話再次對用戶進行身份驗證,或者容許兩個會話同時存在。session
啓用併發會話控制支持的第一步是在web.xml中添加如下偵聽器:
<listener> <listener-class> org.springframework.security.web.session.HttpSessionEventPublisher </listener-class> </listener>
或者將其定義爲Bean - 以下所示:
@Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); }
這對於確保在銷燬會話時通知Spring Security會話註冊表是相當重要。
要爲同一用戶啓用容許多個併發會話的方案,應在XML配置中使用<session-management>元素:
<http ...> <session-management> <concurrency-control max-sessions="2" /> </session-management> </http>
或者,經過Java配置:
@Override protected void configure(HttpSecurity http) throws Exception { http.sessionManagement().maximumSessions(2) }
會話超時後,若是用戶發送的會話ID已過時,則會將其重定向到可經過命名空間配置的URL:
<session-management> <concurrency-control expired-url="/sessionExpired.html" ... /> </session-management>
一樣,若是用戶發送的會話ID未過時但徹底無效,則它們也會被重定向到可配置的URL:
<session-management invalid-session-url="/invalidSession.html"> ... </session-management>
相應的Java配置:
http.sessionManagement() .expiredUrl("/sessionExpired.html") .invalidSessionUrl("/invalidSession.html");
在URL中公開會話信息的安全風險愈來愈大(從2007年的第7位到2013年在OWASP排行榜前10位的第2位)。
從Spring 3.0開始,如今能夠經過在<http>命名空間中設置disable-url-rewriting =「true」來禁用將jsessionid附加到URL的URL重寫邏輯。
或者,從Servlet 3.0開始,也能夠在web.xml中配置會話跟蹤機制:
<session-config> <tracking-mode>COOKIE</tracking-mode> </session-config>
編程方式
servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE));
這將選擇存儲JSESSIONID的位置 - 在cookie或URL參數中。
該框架經過配置在用戶已有會話的狀況但嘗試再次進行身份驗證時,提供了針對典型會話固定攻擊的保護:
<session-management session-fixation-protection="migrateSession"> ...
相應的Java配置:
http.sessionManagement() .sessionFixation().migrateSession()
默認狀況下,Spring Security啓用了此保護(「migrateSession」) - 在身份驗證時,會建立一個新的HTTP會話,舊的會話將失效,舊會話的屬性將被複制。
若是這不是所需的行爲,則可使用其餘兩個選項:
接下來,咱們將討論如何保護會話cookie。 咱們可使用httpOnly和secure標籤來保護咱們的會話cookie:
咱們能夠在web.xml中爲會話cookie設置這些標誌:
<session-config> <session-timeout>1</session-timeout> <cookie-config> <http-only>true</http-only> <secure>true</secure> </cookie-config> </session-config>
從Java servlet 3開始,此配置選項可用。默認狀況下,http-only爲true且secure爲false。
咱們來看看相應的Java配置:
public class MainWebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext sc) throws ServletException { // ... sc.getSessionCookieConfig().setHttpOnly(true); sc.getSessionCookieConfig().setSecure(true); } }
若是咱們使用Spring Boot,咱們能夠在application.properties中設置這些標誌:
server.servlet.session.cookie.http-only=true server.servlet.session.cookie.secure=true
最後,咱們還可使用Filter手動實現此目的:
public class SessionFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; Cookie[] allCookies = req.getCookies(); if (allCookies != null) { Cookie session = Arrays.stream(allCookies).filter(x -> x.getName().equals("JSESSIONID")) .findFirst().orElse(null); if (session != null) { session.setHttpOnly(true); session.setSecure(true); res.addCookie(session); } } chain.doFilter(req, res); } }
只需在web-Context中,使用@Scope註釋聲明的bean:
@Component @Scope("session") public class Foo { .. }
或者使用XML:
<bean id="foo" scope="session"/>
而後,bean能夠簡單地注入另外一個bean:
@Autowired private Foo theFoo;
Spring會將新bean綁定到HTTP Session的生命週期。
原始HTTP會話也能夠直接注入Controller方法:
@RequestMapping(..) public void fooMethod(HttpSession session) { session.addAttribute(Constants.FOO, new Foo(); //... Foo foo = (Foo) session.getAttribute(Constants.Foo); }
當前的HTTP Session也能夠經過原始Servlet API以編程方式得到:
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpSession session= attr.getRequest().getSession(true); // true == allow create
在本文中,咱們討論了使用Spring Security管理Sessions。此外,Spring Reference包含一個很是好的會話管理常見問題解答。
與往常同樣,本文中提供的代碼能夠在Github上獲得。這是一個基於Maven的項目,所以它應該很容易導入和運行。
原文出處:https://www.cnblogs.com/xjknight/p/10897849.html