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

时间:2016-04-22 20:12:31

标签: java spring spring-mvc spring-security

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

  

Authentication中删除SecurityContext以防止并发请求出现问题。

Authentication移除SecurityContext会阻止哪些具体问题?为什么不简单地使会话无效(这是SecurityContextLogoutHandler的另一个责任)足够吗?

如果不清除SecurityContextSecurityContextPersistenceFilter可能会将当前身份验证保留为新的会话ID吗?有效地让用户只使用新会话登录?

4 个答案:

答案 0 :(得分:4)

this commit中添加了

clearAuthentication标记

  

以前,当用户尝试访问时可能会出现竞争情况   一个缓慢的资源,然后注销,这将导致用户没有被记录   现在,来自。的SecurityContextLogoutHandler将从中删除身份验证   SecurityContext可以防止出现这种情况。

它在github上修复了这个issuesame issue)。引用:

  

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

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

  SaveToSessionResponseWrapper应该记住初始HttpSession并检查原始会话是否无效,因此它不会将当前身份验证设置为新会话。

答案 1 :(得分:4)

  

什么是SecurityContextLogoutHandler?

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

  

SecurityContextLogoutHandler的作用是什么?

  1. 它通过修改SecurityContextHolder来执行注销。
  2. 如果isInvalidateHttpSession(),它也会使HttpSession无效 为true且会话不为空。
  3. 它还将从当前删除身份验证 如果clearAuthentication设置为true(默认值),则为SecurityContext。
  4.   

    SecurityContextHolder线程安全吗?

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

    方面也没有任何“线程逻辑”,它们在与建议方法相同的线程上执行。

    归功于@ axtavt

      

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

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

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

    1. 系统会提示用户使用用户名和密码登录。
    2. 系统(成功)验证密码是否正确 用户名。
    3. 获取该用户的上下文信息(其列表为 角色等)。
    4. 为用户建立安全上下文 用户继续执行某些可能受访问控制机制保护的操作,该访问控制机制根据当前安全上下文信息检查操作所需的权限。

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

      1. 获取用户名和密码并将其合并到一个实例中 UsernamePasswordAuthenticationToken(一个实例) 身份验证界面,我们之前看到过。)
      2. 将令牌传递给AuthenticationManager for的实例 验证。
      3. AuthenticationManager返回完全填充的身份验证 验证成功的实例。
      4. 通过调用建立安全上下文 SecurityContextHolder.getContext()。setAuthentication(...),传递 在返回的身份验证对象中。
      5.   

        SecurityContextPersistentFilter

        这个名字很明确。 SecurityContextPersistentFilter接口的目的是将安全上下文存储在某个存储库中。 要完成此任务,筛选器会将作业委派给SecurityContextRepository接口。 Spring为此接口提供了一个默认实现:org.springframework.security.web.context.HttpSessionSecurityContextRepository。这是不言自明的。安全上下文的存储库只是当前的用户HTTP会话。 以下是SecurityContextPersistentFilter

        的XML配置
        <!-- 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" />
        
          

        LogoutFilter

        LogoutFilter负责注销当前用户并使安全上下文无效。使HTTP会话无效的任务再次委托给另一个actor,即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>
        

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

        SecurityContextLogoutHandler在<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>

        注入构造函数参数

        注销操作的HTML网址由<property name="filterProcessesUrl" value="/j_myApplication_logout"/>

        上的filterProcessesUrl参数定义

        资源链接:

        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

答案 2 :(得分:3)

http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html 在请求之间存储SecurityContext

根据应用程序的类型,可能需要采用策略来在用户操作之间存储安全上下文。在典型的Web应用程序中,用户登录一次,然后通过其会话ID进行标识。服务器缓存持续时间会话的主体信息。在Spring Security中,在请求之间存储SecurityContext的责任属于SecurityContextPersistenceFilter,它默认将上下文存储为HTTP请求之间的HttpSession属性。它为每个请求恢复SecurityContextHolder的上下文,并且至关重要的是,在请求完成时清除SecurityContextHolder。 出于安全考虑,您不应直接与HttpSession进行交互。这样做完全没有理由 - 请始终使用SecurityContextHolder。

许多其他类型的应用程序(例如,无状态RESTful Web服务)不使用HTTP会话,并且会在每个请求上重新进行身份验证。但是,包含SecurityContextPersistenceFilter仍然很重要在链中确保在每次请求后清除SecurityContextHolder。

[注意]注意 在单个会话中接收并发请求的应用程序中,将在线程之间共享相同的SecurityContext实例。即使正在使用ThreadLocal,它也是从HttpSession为每个线程检索的相同实例。如果您希望临时更改运行线程的上下文,则会产生影响。如果您只使用SecurityContextHolder.getContext(),并对返回的上下文对象调用setAuthentication(anAuthentication),则Authentication对象将在共享同一SecurityContext实例的所有并发线程中更改。 您可以自定义SecurityContextPersistenceFilter的行为,为每个请求创建一个全新的SecurityContext,防止一个线程中的更改影响另一个。或者您可以在临时更改上下文的位置创建一个新实例。 SecurityContextHolder.createEmptyContext()方法总是返回一个新的上下文实例。

答案 3 :(得分:0)

SecurityContextLogoutHandler以标准的Servlet方式使Servlet会话无效,调用 对HttpSession对象的invalidate方法以及从Spring Security清除SecurityContext的方法。 SecurityContextLogoutHandler实现LogoutHandler接口 传统上,在Java Web应用程序中,用HttpSession对象管理用户会话信息。 在Spring Security(会话清算)中,在较低级别,情况仍然如此, Spring安全性引入了处理会话或用户会话信息的新方法。 在使用Spring Security的应用程序中,您很少直接访问Session对象以检索用户 细节。相反,您将使用SecurityContext(及其实现类)和SecurityContextHolder (及其实施类)。 SecurityContextHolder允许快速访问SecurityContext ,. SecurityContext允许快速访问Authentication对象,Authentication对象允许快速访问 访问用户详细信息。

例如,在编程之后说明了访问认证对象和显示消息

@Controller
@RequestMapping("/admin")
public class AdminController {

@RequestMapping(method = RequestMethod.POST, value = "/movies")
@ResponseBody
public String createMovie(@RequestBody String movie) {
System.out.println("Adding movie!! "+movie);
return "created";
}

@RequestMapping(method = RequestMethod.GET, value = "/movies")
@ResponseBody
public String createMovie() {
UserDetails user = (UserDetails)SecurityContextHolder.getContext().getAuthentication().
getPrincipal();
System.out.println("returned movie!");
return "User "+user.getUsername()+" is accessing movie x";
}
}

一旦完成身份验证,就会创建一个新会话; 创建会话后,它包含用户.on logout u need的信息 不仅要使会话无效,还需要清除会话信息

默认情况下
  `isInvalidateHttpSession(`)  

检查会话是否有效 如果会话有效

setInvalidateHttpSession(boolean invalidateHttpSession)

被调用。如何使会话对象无效,但会话对象仍包含信息。  清除需要调用的会话信息

setClearAuthentication(boolean clearAuthentication)
因此,如果不是第三种方法,

方法就变得线程安全,它可以在低级别检索信息

相关问题