cari

Rumah  >  Soal Jawab  >  teks badan

java - Servlet 如何通过一般请求参数传递 SessionID

我有个项目,希望在 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 里。

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

天蓬老师天蓬老师2767 hari yang lalu811

membalas semua(2)saya akan balas

  • 天蓬老师

    天蓬老师2017-04-17 17:59:18

    搞定了,我查了 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 而已,在客户端对连接做个简单封装也许更方便.

    balas
    0
  • PHP中文网

    PHP中文网2017-04-17 17:59:18

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

    balas
    0
  • Batalbalas