搜尋

首頁  >  問答  >  主體

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 里。

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

天蓬老师天蓬老师2797 天前839

全部回覆(2)我來回復

  • 天蓬老师

    天蓬老师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 而已,在客戶端對連接做個簡單封裝也許更方便.

    回覆
    0
  • PHP中文网

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

    使用 token 的方式,把 token 放在請求頭裡面。要求前端在請求的時候要帶這個 token

    回覆
    0
  • 取消回覆