Spring Security的一個(gè)常用配置就是檢測相同的用戶以不同的session登錄系統(tǒng)。這稱為concurrency control,是session管理一系列配置的一部分。Spring Security的session管理能夠以兩種不同的方式進(jìn)行配置——session fixation protection(固化保護(hù))和concurrency control(并發(fā)控制)。
配置session fixation保護(hù)
Session fixation protection是惡意用戶試圖竊取系統(tǒng)中一個(gè)未認(rèn)證用戶的session,在用戶認(rèn)證后,創(chuàng)建session副本,無需用戶名和密碼來訪問用戶信息的保護(hù)措施。攻擊流程如圖所示。

該類攻擊的主要是利用了用戶認(rèn)證前后使用相同的session這個(gè)漏洞,其保護(hù)措施就是在用戶認(rèn)證后創(chuàng)建一個(gè)新的session,并令舊session失效。
Spring Security默認(rèn)已經(jīng)開啟了Session Fixation Protection。下面的配置等同于默認(rèn)開啟設(shè)置
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//Spring Security的默認(rèn)啟用防止固化session攻擊
.and().sessionManagement().sessionFixation().migrateSession();
}
sessionFixation可以設(shè)置三種方式:
- NONE,不啟用Fixation保護(hù)
- migrateSession,啟用Fixation保護(hù),用戶認(rèn)證后創(chuàng)建新的session,并將舊session的屬性復(fù)制到新session中。
- newSession,啟用Fixation保護(hù),用戶認(rèn)證后創(chuàng)建新的session,但是不復(fù)制舊session的屬性。
配置session concurrency protection
設(shè)置了session fixation protection,自然會(huì)想到控制session的并發(fā)數(shù)量。session并發(fā)控制能夠確保一個(gè)用戶不能同時(shí)擁有超過一定數(shù)量的活躍session。配置Spring Security的session并發(fā)數(shù)非常簡單:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/assets/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/**").hasRole("USER")
.and().formLogin().loginPage("/login.jsp").permitAll().loginProcessingUrl("/login")
.and().logout().permitAll()
//自動(dòng)識(shí)別tokenRepository類型,啟用PersistentTokenBasedRememberMeServices
.and().rememberMe().tokenRepository(persistentTokenRepository())
//Spring Security的默認(rèn)啟用防止固化session攻擊
.and().sessionManagement().sessionFixation().migrateSession()
//設(shè)置session最大并發(fā)數(shù)為1,當(dāng)建立新session時(shí),原session將expired,并且跳轉(zhuǎn)到登錄界面
.maximumSessions(1).expiredUrl("/login.jsp").sessionRegistry(sessionRegistry).and()
.and().csrf().disable();
}
這里設(shè)置session并發(fā)數(shù)為1,當(dāng)用戶在session失效前又創(chuàng)建另一session,則前一個(gè)session失效,并且再次訪問時(shí),自動(dòng)跳轉(zhuǎn)到/loging.jsp,要求用戶再次認(rèn)證。
獲取系統(tǒng)在線用戶總數(shù)
Spring Security會(huì)將認(rèn)證的用戶存儲(chǔ)到Session Registry中,通過該類就可以獲取當(dāng)前在線用戶數(shù)據(jù),配置方法同上。Session Registry依賴HttpSessionEventPublisher,該類注冊到服務(wù)容器中,就可以監(jiān)聽session狀態(tài)的變化,而調(diào)整Session Registry。
配置HttpSessionEventPublisher:
/**
* 以war包形式部署到web容器的啟動(dòng)類
*/
public class ApplicationServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(ApplicationInitializer.class);
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.addListener(new HttpSessionEventPublisher());
}
}
為了獲得當(dāng)前用戶信息,還需要配置一個(gè)Spring Registry Bean,默認(rèn)Spring Security并未提供該類型的bean,我們需要明確聲明,并將其配置給sessionManager()。
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
這樣我們就可以將SessionRegistry注入到需要的地方,獲取其提供的在線用戶信息。
代碼示例:https://github.com/wexgundam/spring.security/tree/master/ch13