0

我正在开发一个基于 Java 的网络应用程序,我们使用 ThreadLocal 来跟踪当前登录的用户。现在,通常它工作得很好。但是,每当会话超时,并且系统尝试访问该变量(从 ThreadLocal 数据),它会给出随机值(一些其他登录用户的值)。理想情况下,它应该返回一个空值。我对这里发生的事情感到困惑。

4

1 回答 1

1

线程是池化的,因此您需要确保为每个请求清除 ThreadLocal。如果您在过滤器中执行此操作,它可能看起来像这样:

private static final ThreadLocal<String> CONTEXT = new ThreadLocal<String>();

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

    try {
        CONTEXT.set(userName);
        chain.doFilter(req,res);
    } finally {
        CONTEXT.remove();
    }
}

否则可能发生的是:

  • UserA 登录并关联到 ThreadA(UserA 在上下文中)
  • UserB 登录并关联到 ThreadB(UserB 在上下文中)
  • UserA 的会话超时并且不再有与其会话关联的用户信息
  • UserA 使用 ThreadB,然后由于再次使用 ThreadB,因此 UserB 似乎在上下文中)

这不仅是一个安全问题,而且还是一个内存泄漏。虽然每个线程只有一个用户填充的线程看起来很小,但它可以加起来。此外,如果放置在 ThreadLocal 中的对象是类型属于战争的 ClassLoader 的对象,那么您将有一个大的PermGen 泄漏,每次取消部署/部署您的应用程序而不重新启动应用程序服务器时都会泄漏您的战争的全部内容。

@LaurentG 是正确的,使用 Spring Security 的方法是使用 SecurityContextHolder。您可以看到 SecurityContextPersistenceFilter 确保 SecurityContext在 finally 块中被清除。

于 2013-07-09T13:25:06.797 回答