SpringSecurity------Session Management(十二)

一、Force Eager Session Creation

有时,总是创建会话是很有价值的,我们可以通过配置ForceEagerSessionCreationFilter来完成:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement(session -> session
            .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
        );
    return http.build();
}

二、Detecting Timeouts

可以配置Spring Security来检测无效会话ID的提交,并将用户重定向到适当的URL,这是通过会话管理(session-management)实现的:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement(session -> session
            .invalidSessionUrl("/invalidSession.htm")
        );
    return http.build();
}

使用上面的配置来检测会话超时,如果用户在登出之后没有关闭浏览器的情况下重新登录,可能会报告一个错误。这是因为执行了登出,会话失效时存储在浏览器的Cookie不会被清除,而且会随着后续请求重新提交。可以使用显示方式在登出之后清除JSESSIONID Cookie(不一定生效,需要在实际环境测试):

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .logout(logout -> logout
            .deleteCookies("JSESSIONID")
        );
    return http.build();
}

三、Concurrent Session Control

如果需要对单个用户登录应用程序的能力施加限制,首先,需要将以下侦听器添加到您的配置中,以保持Spring Security对Session生命周期事件的更新:

@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
    return new HttpSessionEventPublisher();
}

然后,添加以下配置,第二次登录将导致第一次登录的会话失效:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement(session -> session
            .maximumSessions(1)
        );
    return http.build();
}

如果想禁止第二次登录,可以配置如下:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement(session -> session
            .maximumSessions(1)
            .maxSessionsPreventsLogin(true)
        );
    return http.build();
}

如果是基于表单登录,用户将被发送到authentication-failure-url;如果第二次登录是通过非交互机制(non-interactive mechanism)进行的,比如remember-me,则会向客户端发送一个401错误的响应。可以通过设置session-management的session-authentication-error-url属性来指定希望使用的错误处理地址。

四、Session Fixation Attack Protection

会话固定攻击是一种潜在的风险,恶意攻击者可能通过访问站点来创建会话,然后驱使用户使用相同的会话登录(例如,通过向他们发送一个将会话标识当作参数的链接)。Spring Security通过创建一个新的会话或在用户登录时更改会话ID来自动防止这种情况。 如果不需要这种保护,或者它与其他需求冲突,可以使用session-management上的session- fixed -protection属性控制行为,该属性有四个选项:

  • none:不做处理,保留原始会话
  • newSession:创建一个新的会话,不会复制现有会话的数据(Spring Security相关的数据会被复制)
  • migrateSession:创建一个新会话,并将所有现有会话属性复制到新会话中,这是Servlet 3.0或更早的容器中的默认值
  • changeSessionId:不创建新的会话,使用Servlet容器提供的会话固定保护(HttpServletRequest#changeSessionId())。该选项仅在Servlet 3.1 (Java EE 7)和更新的容器中可用。 在旧容器中指定它将导致异常。 这是Servlet 3.1和更新的容器中的默认值。

当发生会话固定保护时,应用程序会发布一个SessionFixationProtectionEvent事件。如果使用的是changeSessionId配置,事件也会通知到任何javax.servlet.http.httpessionidlisteners监听器,因此如果您的代码同时侦听这两个事件,请谨慎使用。

五、SessionManagementFilter

SessionManagementFilter通过对比SecurityContextRepository获取的内容和SecurityContextHolder中的内容来确定当前请求用户是否通过了身份验证,这种验证通常是非交互的身份验证机制(如:pre-authentication,remember-me)。如果存储库包含了一个SecurityContext,SessionManagementFilter不做任何处理。如果没有,并且线程本地包含一个SecurityContext非匿名(non-anonymous)的Authentication对象,SessionManagementFilter假定它们已经通过先前的过滤器进行了身份验证,然后调用配置好的SessionAuthenticationStrategy。

如果当前用户没有经过身份验证,SessionManagementFilter会检查是否请求包含了无效的session ID(比如会话过期),然后会调用InvalidSessionStrategy(如果有配置的话)。最常见的处理方式是重定向到一个固定的URL,SimpleRedirectInvalidSessionStrategy这个标准实现支持这种策略。

六、SessionAuthenticationStrategy

SessionAuthenticationStrategy由SessionManagementFilter和AbstractAuthenticationProcessingFilter使用,因此,如果使用定制的表单登录类, 需要将它注入到这两个类中:

<http>
<custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />
<session-management session-authentication-strategy-ref="sas"/>
</http>

<beans:bean id="myAuthFilter" class=
"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
	<beans:property name="sessionAuthenticationStrategy" ref="sas" />
	...
</beans:bean>

<beans:bean id="sas" class=
"org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" />

注意,如果在实现HttpSessionBindingListener的会话中存储beans(包括 Spring session-scoped beans),使用默认的SessionFixationProtectionStrategy可能会导致问题。

七、Concurrency Control

Spring Security可以控制用户并发身份验证的次数。比如可以阻止一个用户在两个会话中同时登录应用程序,可以使之前的登录过期,也可以在第二次登录的时候报错以限制第二次登录。如果你使用限制第二次登录,那么尚未显式注销的用户直到其原始的会话过期之才能再次登录

需要在web.xml中配置HttpSessionEventPublisher才能使用:

<listener>
	<listener-class>
	org.springframework.security.web.session.HttpSessionEventPublisher
	</listener-class>
</listener>

另外,需要将ConcurrentSessionFilter添加到FilterChainProxy中。 ConcurrentSessionFilter需要两个构造函数参数:sessionRegistry,它通常是SessionRegistryImpl的一个实例;以及sessionInformationExpiredStrategy,它定义了当会话过期时应用的策略。 使用xml的配置方式:

<http>
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />

<session-management session-authentication-strategy-ref="sas"/>
</http>

<beans:bean id="redirectSessionInformationExpiredStrategy"
class="org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy">
<beans:constructor-arg name="invalidSessionUrl" value="/session-expired.htm" />
</beans:bean>

<beans:bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<beans:constructor-arg name="sessionInformationExpiredStrategy" ref="redirectSessionInformationExpiredStrategy" />
</beans:bean>

<beans:bean id="myAuthFilter" class=
"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="sessionAuthenticationStrategy" ref="sas" />
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>

<beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<beans:constructor-arg>
	<beans:list>
	<beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
		<beans:constructor-arg ref="sessionRegistry"/>
		<beans:property name="maximumSessions" value="1" />
		<beans:property name="exceptionIfMaximumExceeded" value="true" />
	</beans:bean>
	<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
	</beans:bean>
	<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
		<beans:constructor-arg ref="sessionRegistry"/>
	</beans:bean>
	</beans:list>
</beans:constructor-arg>
</beans:bean>

<beans:bean id="sessionRegistry"
	class="org.springframework.security.core.session.SessionRegistryImpl" />

将HttpSessionEventPublisher添加到web.xml,每当HttpSession开始或结束时,ApplicationEvent都会被发布到Spring ApplicationContext。 这是至关重要,因为它允许在会话结束时通知SessionRegistryImpl,如果没有它,用户将永远无法在超过会话登录限制时重新登录,即使注销了另一个会话或会话超时。

八、Querying the SessionRegistry for currently authenticated users and their sessions

匹配并发控制会引入一个SessionRegistry,可以在应用程序中直接使用这个bean,因此,即使不需要控制用户的会话数量,设置这些基础组件也是值得的,可以将maximumSession属性设置为-1,以允许无限的会话。如果使用xml配置,可以使用session-registry-alias属性为内部创建的SessionRegistry设置别名,从而提供一个可以注入到您自己的bean中的引用。

SessionRegistry.getAllPrincipals()方法可以获取到当前登录用户列表。SessionRegistry.getAllSessions(Object principal, boolean includeExpiredSessions)方法来列出用户的会话,该方法返回SessionInformation对象的列表。还可以通过在SessionInformation实例上调用expireNow()来终止用户的会话。

通过认证之后执行重定向的机制(比如form-login)不会被SessionManagementFilter检测到,在认证请求期间,过滤器不会被调用, 在这些情况下,必须单独处理会话管理功能。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Session 是一个轻量级的会话管理框架,它基于 Spring SecurityJava Servlet API,旨在提供跨域的会话管理解决方案,简化在分布式应用中管理用户会话的需求。Spring Session 的主要目标是: 1. **跨域会话共享**:Spring Session 允许你在不同的域(通常是指不同域名或端口)之间共享同一个用户的会话,这对于现代的微服务架构和API网关非常有用。 2. **持久化会话**:支持会话数据的持久化,即使用户关闭浏览器,也可以通过服务器存储会话信息,再次访问时能够恢复登录状态。 3. **可配置性**:提供了多种会话存储机制,包括内存、Redis、Memcached、数据库等,可以根据应用需求灵活选择。 4. **与Spring Security集成**:无缝集成到Spring Security框架中,可以轻松管理用户认证和授权。 5. **可扩展性**:Spring Session 提供了对Spring Cloud的集成,使得在分布式环境中会话管理更加容易。 使用 Spring Session 的关键步骤包括: - 配置一个会话工厂,指定会话存储机制。 - 创建一个HttpSessionListener来监听会话创建和销毁事件。 - 配置Spring Security以使用Spring Session进行会话管理。 以下是一个简单的配置示例: ```java @Configuration @EnableCaching @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private HttpSessionStrategy httpSessionStrategy; @Bean public HttpSessionStrategy httpSessionStrategy() { return new SaveOnlyIfNewHttpSessionStrategy(); } @Override protected void configure(HttpSecurity http) throws Exception { // ... http .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .sessionAuthenticationStrategy(sessionAuthenticationStrategy()); } @Bean public SaveOnlyIfNewHttpSessionStrategy sessionAuthenticationStrategy() { return new SaveOnlyIfNewHttpSessionStrategy(httpSessionStrategy); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豢龙先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值