java - Servlet 如何通过一般请求参数传递 SessionID
天蓬老师
天蓬老师 2017-04-17 17:57:18
0
2
836

我有个项目,希望在 REST 接口使用 SessionID 作为 Token,这样能简化和用熟悉的方式处理会话数据,在 URL 附加 ;jsessionid= 太丑,传递 Cookie 的话 APP 开发又嫌麻烦,就想通过普通的 GET/POST 参数或自定义 HTTP BODY 来传递 SessionID。

现在的 Servlet 都不再支持通过 ID 获取 Session,搜到的一些方案,比如用监听器来记录 Session,但我不喜欢这种方式,1是我觉得冗余,2是不想自己存储更不想放在内存里;SessionManager 的话就是自定存储了,目前 tomcat,jetty 等的 session 已经满足我的需求了,没必要找这个麻烦。

我查了下 Tomcat 的源码找到了他的 Request 里有 setRequestedSessionId 的方法,只要在 getSession 之前调用就行,但这不是 ServletRequest 接口里的方法,我的项目不一定运行在 Tomcat 里。

来问问有什么简单的方式解决这个问题没?

天蓬老师
天蓬老师

欢迎选择我的课程,让我们一起见证您的进步~~

Antworte allen(2)
Peter_Zhu

搞定了,我查了 Tomcat,Jetty 各自的 Request (HttpServletRequest 的实现),都通过一个 setRequestedSessionId(String) 来设置会话 id,如是我用反射的方式来获取和调用此方法,在 getSession 之前设置 sessionId,经过在 Jetty 上实验有效,再去试试 Tomcat。这两种容器是我常用的,遇到其他容器再看了。

代码简简单单:

    try {
        request.getClass ()
             .getMethod("setRequestedSessionId", String.class)
             .invoke   (request , id);
    } catch ( NoSuchMethodException ex) {
        // Log
    } catch (IllegalAccessException |
           IllegalArgumentException |
          InvocationTargetException ex) {
        // Log
    }

呵呵!

需要注意,必须在当前请求首次调用 getSession 之前执行才行,尤其注意上层是否有 Filter 中用到 Session


2016/05/21 更新实验结果

以上方法 SessionID 是可以换掉的,但是却取不出来 Session,因取时还会对 Session 进行验证,跟踪 Jetty 的源码发现,设置 Session 对象是在初始化 Request 的时候,如下图:

此时还没进行到 Servlet 和 Filter,无从下手,因此看来重设没那么简单。

以上只对 Jetty 做了实测,结果失败。Tomcat 没实验,看源码有 changeSessionId(String) 方法,看逻辑应该是可以的。


2016/05/21 再次更新结果

经过不断的折腾,用以下代码重设 sessionId 成功:

    try {
        Object obj;
        obj = req.getClass ()
           .getMethod("getSessionManager")
           .invoke   (req);
        obj = obj.getClass ()
           .getMethod("getHttpSession" , String.class)
           .invoke   (obj, sid);
        req.getClass ()
           .getMethod("setSession", HttpSession.class)
           .invoke   (req, (HttpSession) obj);
    } catch ( NoSuchMethodException ex ) {
        // Log
    } catch (IllegalAccessException  |
           IllegalArgumentException  |
          InvocationTargetException ex ) {
        // Log
    }

在此之后执行的程序什么也不用变,可正常使用 request.getSession() 来读写 Session, 此方法针对 Jetty 写的.


2015/05/22 Tomcat 实测更新

吃完早饭无聊,跟踪了下 Tomcat 的代码,使用 Tomcat 7,8 两个版本,发现其交给用户 Servlet 的 Request 对象是一个叫 RequestFacade 的代理类,此类仅对 HttpServletRequest 接口的方法做了实现,隐藏了他的 Request 对象,因此无法调用到 org.apache.catalina.connector.Request 的 setRequestedSessionId 等方法。

看来也只能针对 Jetty 实现此 Hack 了。


结果虽然不太乐观,且没准 Jetty 在之后的版本里也会隐藏那些方法,不过这个实验过程又对这两种应用容器有了更进一步的了解。Cookie 也好,URL Path Parameter 也好,GET/POST 参数也好,只是在请求数据的不同位置携带 Session Token 而已,在客户端对连接做个简单封装也许更方便.

Ty80

使用 token 的方式,把 token 放在请求头里面。要求前端在请求的时候要带上这个 token

Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage