admin

填坑:H5 APP 使用 JSESSIONID 保持会话登录
前言这段时间给电影网站加了收费在线观看的权限,由于之前的 APP 没有添加登录模块,所以现在必须得添加上了。APP...
扫描右侧二维码阅读全文
25
2018/02

填坑:H5 APP 使用 JSESSIONID 保持会话登录

前言

这段时间给电影网站加了收费在线观看的权限,由于之前的 APP 没有添加登录模块,所以现在必须得添加上了。APP 基于 H5 MUI 开发,在实现的过程中真的是碰得焦头烂额的。

过程

H5 开发 APP 无非就是利用 WebView 操作 html 代码,写个登录页面简直就是顺手拈来,但是!写完登录,发现登录成功后再次发起其他的 ajax 请求,依旧是未登录状态,即 ajax 登录后服务器 response 的 Set-Cookie 在 WebView 中不起作用。
既然如此,那么就在登陆后保存服务器返回的 JSESSIONID,后面的 ajax 请求添加上 cookie,无奈 mui.ajax headers 添加 cookie 不能成功!
到 DCloud 社区搜索相关问答,官方说 plus.navigator.setCookie() 可以设置 WebView 的 Cookie,于是去尝试一下,发现没点作用,几经折腾,发现是离线打包的原因,在 Hbuilder 中用基座调试是没问题的,没办法由于播放器部分必须用 Android 原生代码开发,所以必须离线打包,MUI 的这个 H5 开发 APP 就是一坑,不想多说了,这个问题根本无从下手去找解决方法。
此时,代码没问题,是离线打包 SDK 的问题,头都大了,心中一万匹草泥马奔腾起来,发誓再也不用 MUI 开发 APP 了。

解决方案

针对这种情况,解决办法当然还是有的,只不过繁琐一些罢了。
方案一:
将 H5 中的 ajax 交由 Android 原生代码去做,这样一来设置 Http 请求的 Cookie 就不可能会有问题了,实现需做的事情:编写插件接口用 Java 代码实现带 cookie 的 http 请求,在 js 代码中调用此接口。如果 SDK 离线打包没问题的话,原本 plus.navigator.setCookie() 一句代码就能解决的事变得这么繁琐,不采用!
方案二:
对 Tomcat 服务器不熟悉的打破脑袋估计也想不到此方案。有点 Http 协议常识的人都知道,浏览器与服务器保持会话登录状态通常是利用 session 来实现的,当然了 cookie 也能,但是不安全。
实际上 session 的实现方案也可能需要借助 cookie(不是必需的),对于 Java Web,浏览器访问服务器,都会产生一个 JSESSIONID,大多数情况下我们看到的是存在于 Cookie 中,对于早期的一些网站都是暴露在 URL 地址中的,正因如此,可能很多人就想不到此方案。
既然 WebView 中 ajax 设置 Cookie 不成功,那么能够将 JSESSIONID 作为 http 请求参数传给服务器后台吗?
最初我的想法就是这样的:

  1. ajax 登录,SpringMVC Controller 中 session.getId() 获取到 JSESSIONID 返回给客户端。
  2. 接收登录返回结果,将 JSESSIONID 通过 plus.storage.setItem() 存到本地。
  3. 进行需要权限的 ajax 请求时从本地获取 JSESSIONID 并拼接到 url 中。

上面做法有个难点就是,后端获取到 JSESSIONID 后如何通过 JSESSIONID 取得对应的 HttpSession 对象,经过一方搜索,几乎没有什么好的方案,唯一可行的就是通过实现 HttpSessionListener 接口,自己将所有的 session 都用一个 Map 保存起来,这样一来就可以通过这个 Map 来根据 JSESSIONID 获取对应的 session 对象了,但是,此方案不够优雅,Tomcat 本身就存储了所有的 session,这样做显得有点多此一举,并且,session 的时效性又该如何控制?
到这里,内心是崩溃的。
不到黄河心不死,关键点在于 JSESSIONID,于是搜索 JSESSIONID,很多文章都是说如何去掉 url 中的 JSESSIONID,看到这里,虽然不是我要找的答案,但是正好相反,我要做的是如何把这个 JSESSIONID 不通过 cookie 传给服务器,而是通过 url 传给后台。
于是终于找到答案:
前面也说了一下,session 实现方案是可以借助 cookie 来传递 JSESSIONID 或者在 url 中来传递 JSESSIONID 的,只是我没有想到,url 传递 JSESSIONID 不需要我们手动在后端来根据 JSESSIONID来获取对应的 session 对象,服务器都给我们做好了的。
之所以会有 url 传递JSESSIONID这种方案,是因为当客户端禁止了 cookie 后,为了能够客户端与服务器保持会话而做的。
到此,对于服务器的 session 又有了一个新的认识。
最终解决方案就是:
http 请求地址中是用如下方式携带JSESSIONID的:

http://xxx.com/action;jsessionid=xxxxxxxxxxxx

和普通的 http 参数不同,它是以分号开始追加到地址后面的(参数是以问号追加)。
这样一来,服务器会自动地获取 session_id,并找到对应的 HttpSession 对象,并不需要我们手动地去获取(手动获取在前面也分析过了,没有什么好的实现方法)。所以,没错,就是这么简单,WebView cookie 设置不成功有什么大不了,直接利用 url 传递 session_id 简直方便快捷。
但是,由于之前 web.xml 配置出了点差错,那是因为服务器 session 错乱,找不到问题所在,就把 url 传递 session_id 给禁止了,也就是前面所说的很多文章关于去掉 url 中的 jsessionid 的,在 web.xml中加了下面配置:

<session-config>
    <tracking-mode>COOKIE</tracking-mode>
</session-config>

这简直是坑爹,如此设置虽然能去掉 url 中的 jsessionid,是为了好看吗?一旦客户端禁止 cookie,需要登录的会话操作就全部用不了了,现在想想,当时真的是病急乱投医。
最后老老实实去掉该段配置,就能够通过 url 的方式来传递 jsessionid 来保持登录会话状态了,问题得以解决。

Last modification:February 25th, 2018 at 01:12 am
If you think my article is useful to you, please feel free to appreciate

Leave a Comment