SpringSecurity中文文档—Authentication—Session Management

8 篇文章 1 订阅
6 篇文章 1 订阅

Detecting Timeouts

您可以将Spring Security配置为检测无效会话ID的提交,并将用户重定向到适当的URL。这是通过会话管理元素实现的:

@Override
protected void configure(HttpSecurity http) throws Exception{
    http
        .sessionManagement(session -> session
            .invalidSessionUrl("/invalidSession.htm")
        );
}

请注意,如果使用此机制检测会话超时,如果用户注销,然后在不关闭浏览器的情况下重新登录,则可能会错误地报告错误。这是因为当您使会话无效时,会话cookie不会被清除,即使用户已注销,也会重新提交。您可以在注销时显式删除JSESSIONID cookie,例如,在注销处理程序中使用以下语法:

@Override
protected void configure(HttpSecurity http) throws Exception{
    http
        .logout(logout -> logout
            .deleteCookies("JSESSIONID")
        );
}

不幸的是,这不能保证适用于每个servlet容器,所以您需要在您的环境中测试它。
如果您在代理后运行应用程序,还可以通过配置代理服务器删除会话cookie。例如,使用Apache HTTPD的mod_头,下面的指令将删除JSESSIONID cookie,方法是在响应注销请求时使其过期(假设应用程序部署在路径/教程下):

<LocationMatch "/tutorial/logout">
Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 1970 00:00:00 GMT"
</LocationMatch>

Concurrent Session Control

如果您希望限制单个用户登录应用程序的能力,Spring Security通过以下简单的添加来支持这种开箱即用的功能。首先,您需要将以下侦听器添加到配置中,以保持Spring Security更新会话生命周期事件:

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

然后将以下行添加到application context中:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .sessionManagement(session -> session
            .maximumSessions(1)
        );
}

这将防止用户多次登录——第二次登录将导致第一次登录无效。通常情况下,您希望阻止第二次登录,在这种情况下,您可以使用:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .sessionManagement(session -> session
            .maximumSessions(1)
            .maxSessionsPreventsLogin(true)
        );
}

第二次登录将被拒绝。“拒绝”的意思是,如果使用基于表单的登录,用户将被发送到身份验证失败url。如果第二次身份验证是通过另一个非交互机制进行的,例如“记住我”,则会向客户端发送一个“未经授权”(401)错误。如果您想使用错误页面,可以将属性session-authentication-error- url添加到session management元素中。
如果要使用自定义的身份验证过滤器进行基于表单的登录,则必须显式配置并发会话控制支持。有关更多详细信息,请参阅会话管理一章。

Session Fixation Attack Protection

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

  • none :不做任何事情,保留原会话。
  • newSession:创建一个新的“干净”会话,而不复制现有会话数据(Spring安全相关属性仍将被复制)。
  • migrateSession :创建一个新会话,并将所有现有会话属性复制到新会话。这是Servlet 3.0或更早版本容器中的默认值。
  • changeSessionId :不要创建新会话。相反,使用Servlet容器HttpServletRequest#changeSessionId()提供的会话固定保护。此选项仅在Servlet 3.1(Java EE 7)和更新的容器中可用。在旧容器中指定它将导致异常。这是Servlet 3.1和更新的容器中的默认值。
    当会话固定保护发生时,会导致在应用程序上下文中发布SessionFixationProtectionEvent。如果使用changeSessionId,这种保护也会导致任何javax.servlet.http.HttpSessionIdListeners收到通知,因此如果代码同时侦听这两个事件,请小心。有关更多信息,请参阅会话管理一章。

SessionManagementFilter

SessionManagementFilter根据SecurityContextHolder的当前内容检查SecurityContextRepository的内容,以确定用户在当前请求期间是否已通过身份验证,通常是通过非交互式身份验证机制,如预验证或记住我[1]。如果存储库包含security context,则filter 不执行任何操作。如果没有,并且 thread-local SecurityContext包含一个(non-anonymous)身份验证对象,则过滤器会假定它们已被堆栈中的前一个过滤器身份验证。然后,它将调用已配置的SessionAuthenticationStrategy。
如果用户当前未通过身份验证,筛选器将检查是否已请求过的无效会话ID(例如,由于超时),并将调用配置的InvalidSessionStrategy(如果已设置)。最常见的行为就是重定向到一个固定的URL,这被封装在标准实现SimpleDirectInvalidSessionStrategy中。如前所述,在通过命名空间配置无效会话URL时,也会使用后者。

SessionAuthenticationStrategy

SessionAuthenticationStrategy由SessionManagementFilter和AbstractAuthenticationProcessingFilter使用,因此,如果您使用的是自定义表单登录类,则需要将其注入这两个类中。在本例中,将名称空间和自定义bean组合在一起的典型配置可能如下所示:

<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" />

Concurrency Control

Spring Security能够防止主体对同一应用程序进行超过指定次数的并发身份验证。许多ISV利用这一点来实施许可,而网络管理员喜欢这一功能,因为它有助于防止人们共享登录名。例如,您可以阻止用户“蝙蝠侠”从两个不同的会话登录到web应用程序。您可以终止他们以前的登录,也可以在他们再次尝试登录时报告错误,从而阻止第二次登录。请注意,如果使用第二种方法,未明确注销(例如,刚刚关闭浏览器)的用户将无法再次登录,直到其原始会话过期。
namespace支持并发控制,因此请查看前面的namespace章节以了解最简单的配置。不过有时候你需要定制一些东西。
该实现使用了SessionAuthenticationStrategy的专用版本,称为ConcurrentSessionControlAuthenticationStrategy。
以前,并发身份验证检查是由ProviderManager进行的,它可以注入ConcurrentSessionController。后者将检查用户是否试图超过允许的会话数。然而,这种方法要求提前创建HTTP会话,这是不可取的。在Spring Security 3中,用户首先由AuthenticationManager进行身份验证,一旦他们成功通过身份验证,就会创建一个会话,并检查是否允许他们打开另一个会话。
要使用并发会话支持,您需要将以下内容添加到web.xml:

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

此外,还需要将ConcurrentSessionFilter添加到FilterChainProxy。ConcurrentSessionFilter需要两个构造函数参数:sessionRegistry(通常指向SessionRegistryImpl的实例)和SessionInformation ExpiredStrategy(定义会话过期时应用的策略)。使用namespace创建FilterChainProxy和其他默认bean的配置可能如下所示:

<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" />

将listener添加到web.xml使ApplicationEvent在每次HttpSession开始或结束时发布到Spring ApplicationContext。这很关键,因为它允许在会话结束时通知SessionRegistryImpl。如果没有它,用户将永远无法在超过会话许可后再次登录,即使他们退出另一个会话或会话超时。

Querying the SessionRegistry for currently authenticated users and their sessions

通过namespace或使用普通bean设置并发控制有一个有用的副作用,即为您提供对SessionRegistry的引用,您可以直接在应用程序中使用该引用,因此即使您不想限制用户可能拥有的会话数,无论如何,建立基础设施可能是值得的。可以将maximumSession属性设置为-1以允许无限会话。如果您使用的是namespace,那么可以使用session-registry-alias属性为内部创建的SessionRegistry设置别名,从而提供一个可以注入到自己bean中的引用。
getAllPrinciples()方法为您提供当前经过身份验证的用户的列表。可以通过调用getAllSessions(Object principal,boolean includeExpiredSessions)方法列出用户的会话,该方法返回会话信息对象的列表。还可以通过在SessionInformation实例上调用expireNow()使用户的会话过期。当用户返回应用程序时,他们将无法继续。例如,您可能会发现这些方法在管理应用程序中很有用。有关更多信息,请查看Javadoc。
SessionManagementFilter不会检测到通过在身份验证后执行重定向(例如表单登录)的机制进行的身份验证,因为在身份验证请求期间不会调用filter 。在这些情况下,会话管理功能必须单独处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值