SecurityContextLogoutHandler的clearAuthentication如何不是线程安全的?

vpi*_*mph 9 java spring spring-mvc spring-security

Spring SecurityContextLogoutHandler注意到该clearAuthentication标志用于:

Authentication从中删除SecurityContext以防止并发请求的问题.

Authentication从中删除了什么具体问题SecurityContext?为什么不是简单地使会话无效(这是另一个责任SecurityContextLogoutHandler)就足够了?

通过不清除SecurityContext是否SecurityContextPersistenceFilter可能将当前身份验证保留为新的会话ID?有效地让用户只使用新会话登录?

Sky*_*ker 5

什么是 SecurityContextLogoutHandler?

SecurityContextLogoutHandler 是一个实现 LogoutHandler 的处理程序。

SecurityContextLogoutHandler 的作用是什么?

  1. 它通过修改SecurityContextHolder来执行注销。
  2. 如果 isInvalidateHttpSession() 为 true 并且会话不为 null,它也会使 HttpSession 无效。
  3. 如果clearAuthentication 设置为true(默认),它还会从当前SecurityContext 中删除Authentication。

SecurityContextHolder 线程安全吗?

是的,使用默认策略 (MODE_THREADLOCAL) 是线程安全的(只要您不尝试动态更改策略)。但是,如果您希望生成的线程继承父线程的SecurityContext,则应该设置MODE_INHERITABLETHREADLOCAL。

此外,方面没有任何“线程逻辑”,它们与建议的方法在同一线程中执行。

感谢@axtavt

Spring Security 中的身份验证是什么?

身份验证:框架尝试使用提供的凭据来识别最终用户。可以针对插入 Spring Security 的第三方系统进行身份验证。

让我们考虑一个每个人都熟悉的标准身份验证场景。

  1. 系统会提示用户使用用户名和密码登录。
  2. 系统(成功)验证用户名的密码是否正确。
  3. 获取该用户的上下文信息(他们的角色列表等)。

为用户建立安全上下文。用户继续执行可能会受到访问控制机制保护的某些操作,该访问控制机制根据当前安全上下文信息检查操作所需的权限。

前三项构成了身份验证过程,因此我们将了解这些过程在 Spring Security 中是如何发生的。

  1. 获取用户名和密码并将其组合到 UsernamePasswordAuthenticationToken 的实例中(我们之前看到的 Authentication 接口的实例)。
  2. 该令牌被传递到 AuthenticationManager 的实例进行验证。
  3. 身份验证成功后,AuthenticationManager 返回完全填充的身份验证实例。
  4. 安全上下文是通过调用SecurityContextHolder.getContext().setAuthentication(...)建立的,传入返回的身份验证对象。

安全上下文持久过滤器

这个名字已经很明确了。SecurityContextPersistentFilter 接口的目的是将安全上下文存储在某个存储库中。为了完成此任务,过滤器将作业委托给 SecurityContextRepository 接口。Spring为此接口提供了默认实现:org.springframework.security.web.context.HttpSessionSecurityContextRepository。这是不言自明的。安全上下文的存储库就是当前用户的 HTTP 会话。下面是 XML 配置SecurityContextPersistentFilter

<!-- Filter to store the Authentication object in the HTTP Session -->   
<bean id="securityContextPersistentFilter"
    class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
    <property name="securityContextRepository" ref="securityContextRepository" />
</bean>


<bean id="securityContextRepository"
    class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />
Run Code Online (Sandbox Code Playgroud)

注销过滤器

LogoutFilter 负责注销当前用户并使安全上下文失效。使 HTTP 会话失效的任务再次委托给另一个参与者,即 SecurityContextLogoutHandler。

该处理程序被注入到 LogoutFilter 构造函数中:

<bean id="logoutFilter"
    class="org.springframework.security.web.authentication.logout.LogoutFilter">
    <constructor-arg value="/pages/Security/logout.html" />
    <constructor-arg>
        <list>
            <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
        </list>
    </constructor-arg>
    <property name="filterProcessesUrl" value="/j_myApplication_logout"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

<constructor-arg value="/pages/Security/logout.html" />- 它定义注销页面的 URL。

SecurityContextLogoutHandler 作为构造函数参数注入<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>

注销操作的 HTML URL 由 filterProcessesUrl 参数定义,位于<property name="filterProcessesUrl" value="/j_myApplication_logout"/>

资源链接:

  1. https://doanduyhai.wordpress.com/2012/01/22/spring-security-part-i-configuration-and-security-chain/
  2. https://doanduyhai.wordpress.com/2012/02/05/spring-security-part-ii-securitycontextpersistentfilter-logoutfilter/
  3. http://shazsterblog.blogspot.com/2014/02/spring-security-custom-filterchainproxy.html
  4. http://docs.spring.io/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/web/context/SecurityContextPersistenceFilter.html


Ily*_*lya 4

clearAuthentication在此提交中添加了带有注释的标志

以前,当用户尝试访问慢速资源然后注销时,可能会出现竞争条件,从而导致用户无法注销。

SecurityContextLogoutHandler 现在将从 SecurityContext 中删除身份验证以防止出现这种情况。

它解决了这个问题( github上有同样的问题)。引用:

如果会话从另一个线程失效,并且 SecurityContextPersistenceFilter 执行需要大量时间,则 HttpSessionSecurityContextRepository 会恢复会话的身份验证。

我使用 Spring + JSF + DWR 框架 + GWT 事件服务(ajax 推送)。在任何时候,至少有一个线程在服务器端等待推送事件。该请求由 SecurityContextPersistenceFilter 处理,它会记住请求到达服务器时的身份验证。如果在此过滤器的处理过程中,会话正在失效(通过在管理区域中按 id 使会话失效的另一个选项卡中单击注销),则 HttpSessionSecurityContextRepository 将过时的身份验证放入新会话(由 JSF 框架创建,因此会话为在处理 SecurityContextPersistenceFilter 期间发生更改)。如果将一些处理延迟插入到 SecurityContextPersistenceFilter 中,则可以轻松重现。

SaveToSessionResponseWrapper 应记住初始 HttpSession 并检查原始会话是否已失效,以便它不会将当前身份验证设置为新会话。