3

根据 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,顺便说一句。

4

2 回答 2

1

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

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

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

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

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

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

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

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

于 2013-08-18T21:34:58.287 回答
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);
}
于 2021-01-06T14:13:36.560 回答