原文: 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. Conclusion
...
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>