原文: https://www.baeldung.com/spring-security-session
1. Overview
這裏將講一下 how spring security allows us to control our HTTP sessions
這種控制的範圍從session timeout到enabling concurrent session及其它高級security configs.
2. when is the session created?
咱們能夠精確控制session何時被創建,及spring security怎樣和它交互:
always - a session will always be created if one doesn't already exist
ifRequired - a session will be created only if required (default)
never - the framework will never create a session ifself but it will use one if it already exists
stateless - no session will be created or used by spring security
<http create-session="ifRequired"> ... </http>
java config
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
}
若是使用stateless, 將會跳過spring security filter chain - 主要session相關部分:
HttpSessionSecurityContextRepository, SessionManagementFilter, RequestCacheFilter
these more strict control mechanisms have the direct implication(隱含) that COOKIES ARE NOT USED and
so EACH AND EVERY REQUEST NEEDS TO BE RE-AUTHENTICATED.
主要用於REST APIs
3. Under The Hood
執行Authentication process前, spring security將運行一個filter - 它負責在requests之間存儲Security Context:
SecurityCotnextPersistenceFilter.
context將根據一個策略(strategy)進行存儲 - HttpSessionSecurityContextRepository(默認) - 這將使用Http Session做爲存儲
對於stateless, 這個strategy被替換成另外一個 - NullSecurityContextRepository.
4. Concurrent Session Control
當一個已經認證過的用戶再次試着去authenticate, the application能以幾種方式之一處理那個事件。
或者invalidate the active session of user,而後authenticate the user again with a new session,
或者容許兩個sessions同時存在
1.容許同時存在的第一步 (web.xml)
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
or:
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
這確保當session is destroyed, spring security session registry能被通知到
第二步, 爲了容許同時存在:
<http ...>
<session-management>
<concurrency-control max-sessions="2" />
</session-management>
</http>
or, via java configuration
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().maxmumSessions(2);
}
5. Session Timeout
session 超時後,若是用戶發送了一個with EXPIRED SESSION ID的請求,這些請求將被redirected到一個URL,
xml配置的URL:
<session-management>
<concurrency-control expired-url="/sessionExpired.html" .../>
</session-management>
相似,若是session無效(invalid), 重定向的url:
<session-management invalid-session-url="/invalidSession.html">
...
</session-management>
相應的java config
http.sessionManagement()
.expiredUrl("/sessionExpired.html")
.invalidSessionUrl("/invalidSession.html");
6. Prevent using URL paramenters for Session Tracking
<http> 添加disable-url-rewriting="true" 禁止 url rewrite
web.xml
<session-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
代碼方式:
servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE));
這選擇在哪存放JSESSIONID, in the cookie or in a URL parameter.
7. Session Fixation Proection with Spring Security
會話固定:
防護:spring security在用戶登陸後,從新生成一個session id
配置當用戶再次authenticate,發生什麼
<session-management session-fixation-protection="mirgateSession"> ...
java config
http.sessionManagement()
.sessionFixation().migrateSession()
上面是spring security的默認配置,old session的屬性會被複制過來
其它配置:
none: 原來的session不會invalidated
newSession: 新建會話,不使用old session裏的任何屬性
8. Working with the session
session scope的bean定義: 使用@Scope annotation
8.1 Session Scoped Beans
@Component
@Scope("session"
public class Foo { .. }
xml:
<bean id="foo" scope="session"/>
而後,the bean can simply be injected into another bean.
@Autowired
private foo Foo;
And spring will bind the new bean to the lifecycle of the HTTP session
8.2 Injecting the Raw Session into a Controller
the raw HTTP Session can alse be injected directly into a Controller method.
@RequestMapping(...)
public void fooMethod(HttpSession session) {
session.addAttribute(Constants.FOO, new Foo());
...
Foo foo = (Foo) session.getAttribute(Constants.FOO);
}
8.3 Obtaining the Raw Session
the current HTTP Session can also be obtained programmatically via the RAW Servlet API:
ServletRequestAttributes attr = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();
HttpSession session = attr.getRequest().getSession(true); // true = allow create
9. Conclusionhtml
...
OVER
本身加點:(from spring session chapter 5)
1. spring session透明集成HttpSession, 好處:
.支持集羣的sessions.
.Restful APIs: spring session allows providing session IDs in headers to work with Restful APIs.
2. 和spring security集成
1. remember me
...
2. spring security concurrent session control
這個支持集羣會話
要自定義一個Spring security's SessionRegistry接口的實現.
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private FindByIndexNameSessionRepository<Session> sessionRepository;
@Bean
SpringSessionBackedSessionRegistry sessionRegistry() {
return new SpringSessionBackedSessionRegistry<>(this.sessionRepository);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// other config goes here ...
.sessionManagement().maximumSessions(2)
.sessionRegistry(sessionRegistry());
}
xml:
<security:http>
<security:session-management>
<security:concurrency-control max-sessions="2" sesssion-registry-ref="sessionRepostory"/>
</security:session-management>
</security:http>
<bean id="sessionRegistry" class="org.springframework.session.security.SpringSessionBackedSessionRegistry">
<constructor-arg ref="sessionRepository"/>
</bean>
java