【问题标题】:Overriding Tomcat's method of getting sessionid from the request覆盖 Tomcat 从请求中获取 sessionid 的方法
【发布时间】:2013-08-20 15:15:12
【问题描述】:

根据 Java EE 标准,Tomcat 允许请求以两种方式指定其现有会话 ID:1) 通过 cookie; 2) 通过“路径参数”(不是常规参数;路径参数的格式为http://host/path/file.ext;jsessionid=xxx?a=b&c=d... - 请注意“;”以及查询字符串仅在路径参数之后开始的事实)。我想要的是在“?”之后的查询字符串中将请求中的会话 ID 作为常规参数传递,例如 http://host/path/file.ext?jsessionid=xxx

当请求到达我可以拦截它并更改容器确定会话 ID 的方式(例如在过滤器或 Servlet 中)时,为时已晚。我想改变的行为是在初始处理来自客户端的请求。出于所有显而易见的原因,我想要避免做的是更改 Coyote 或 Tomcat 代码并自己重建 Tomcat。我更愿意做的是覆盖适当的代码并配置 Tomcat 以使用该代码来确定请求的会话 ID。这似乎是不可能的,但我希望我错了。

我知道以这种方式获取会话 ID 是不标准的;我知道使用 cookie 或路径参数都是跟踪会话状态的好方法;我知道将会话 ID 放在实际的查询字符串中会带来潜在的问题。无论如何我都需要这样做。

运行 Tomcat 7,顺便说一句。

【问题讨论】:

  • 您似乎有充分的理由这样做。可以分享给我们吗?
  • @JB Nizet - 当然。我们对我们的用户说,“我们不使用 cookie,期间。”我们的应用程序与隐私相关,并且能够说这是一件好事。现在,会话 cookie 当然与寿命更长的 cookie 不同,但许多用户失去了这种区别。所以这是关于隐私的感知,真的。无论如何,这意味着我需要通过 URL 保持会话(使用所有防止劫持的保护措施,obv)。但是在提供用户可以保存的内容时,“路径参数”格式会混淆一些浏览器(一些浏览器将 jsessionid 作为文件名的一部分)。
  • @Will Hartung - 非常有帮助,谢谢。是的,你说得对,我们必须在请求生命周期的早期小心解析请求中的参数。出于这个原因,我不会使用getParameter();我只是从查询字符串中解析出来。 (正如您还指出的那样,这意味着我的会话 ID 参数无法发布,但没关系,因为 POST URL 仍然可以附加查询字符串。)

标签: tomcat httpsession jsessionid


【解决方案1】:

您可以在不更改任何 Tomcat 代码的情况下执行此操作。这是一个示例 http 过滤器。显然它应该在任何其他过滤器之前运行:

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    final String sessionId = servletRequest.getParameter("jsessionId");
    if (servletRequest instanceof org.apache.catalina.connector.RequestFacade) {
        try {
            Field tomcatRequestField = servletRequest.getClass().getDeclaredField("request");
            tomcatRequestField.setAccessible(true);
            Request tomcatRequest = (Request) tomcatRequestField.get(servletRequest);
            if (sessionId != null) {
                tomcatRequest.setRequestedSessionId(sessionId);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            LOG.error("Error", e);
        }
    }
    filterChain.doFilter(servletRequest,servletResponse);
}

【讨论】:

    【解决方案2】:

    最简单的方法是从源代码构建 Tomcat,然后破解 CoyoteAdapter.java 类。

    这是此代码所在的位置,但它不是代码中易于扩展的部分,您只需插入一点代码即可拦截这部分请求管道。

    您可以变得聪明并实现自己的依赖于您自己的 CoyoteAdapter 的连接器,而不是仅仅“就地”破解它,但最终您仍然会遇到跟上更新等维护问题。

    您还需要小心,因为通常请求参数不会“解析”,直到有东西请求它们,并且通常直到实际用户代码才完成(我不相信它在点击之前在管道中完成用户代码)。

    这很重要,因为对于 GET 而言,参数解析是在请求标头之外完成的,而对于 POST,它是基于内容的。如果你向请求请求一个参数,它并不关心它是一个 POST 还是一个 GET 并且会自动“做正确的事情”。

    这意味着,如果您从 POST 请求请求参数,管道将在用户应用程序代码之前使用输入流(它开始指向请求有效负载,在标头之后)。取决于用例,但有些应用需要原始流,因此您必须小心使用内置的请求参数逻辑,而不是对原始 URL 本身进行操作。

    你也可以通过一个简单的过滤器来解决这个问题,然后你可以将 HttpServletRequest 转换为底层的 Tomcat 实现(我现在不知道他的名字),然后在上面调用“setSessionID”代码.不知道在处理周期中是否为时已晚,很可能是。

    所以,它可以做到,看起来很简单,但不是通过任何真正规定的扩展方式。官方方法是克隆 tomcat 连接器以调用您自己的 CoyoteAdapter 版本,并在 server.xml 中进行配置。但如果你愿意维护自己的 tomcat 版本,直接破解 CoyoteAdapter 会容易得多。

    【讨论】:

      猜你喜欢
      • 2013-05-30
      • 1970-01-01
      • 2019-06-21
      • 2010-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-04
      相关资源
      最近更新 更多