我有个项目,希望在 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 里。
来问问有什么简单的方式解决这个问题没?
搞定了,我查了 Tomcat,Jetty 各自的 Request (HttpServletRequest 的实现),都通过一个 setRequestedSessionId(String) 来设置会话 id,如是我用反射的方式来获取和调用此方法,在 getSession 之前设置 sessionId,经过在 Jetty 上实验有效,再去试试 Tomcat。这两种容器是我常用的,遇到其他容器再看了。
代码简简单单:
呵呵!
需要注意,必须在当前请求首次调用 getSession 之前执行才行,尤其注意上层是否有 Filter 中用到 Session
2016/05/21 更新实验结果
以上方法 SessionID 是可以换掉的,但是却取不出来 Session,因取时还会对 Session 进行验证,跟踪 Jetty 的源码发现,设置 Session 对象是在初始化 Request 的时候,如下图:
此时还没进行到 Servlet 和 Filter,无从下手,因此看来重设没那么简单。
以上只对 Jetty 做了实测,结果失败。Tomcat 没实验,看源码有 changeSessionId(String) 方法,看逻辑应该是可以的。
2016/05/21 再次更新结果
经过不断的折腾,用以下代码重设 sessionId 成功:
在此之后执行的程序什么也不用变,可正常使用 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 而已,在客户端对连接做个简单封装也许更方便.
使用 token 的方式,把 token 放在请求头里面。要求前端在请求的时候要带上这个 token