问题描述
在开发环境中,皓优企后台管理系统的前端服务器地址为:http://192.168.1.39:8001/dist/ ,后端接口地址http://192.168.1.230:81/managment。在Chrome浏览器中输入输入http://192.168.1.39:8001/dist/即会进入登录页面。在登录页面输入合法的用户名和密码以及正确的验证码,登录页反复提示“验证码错误”。该问题在360浏览器和firefox浏览器上都没有,目前只在Chrome浏览器上出现。
问题分析
打开Chrome开发者工具,在network栏目中查看请求和响应参数。可以看到响应头中有set-cookie项,比如:Set-Cookie: JSESSIONID=EF8C88B741473AC36CE395668FCBB7B4。同一个页面的多个请求,返回的JSESSIONID都不一样。这个值很关键,一个新的JSESSIONID意味着服务器又产生一个新的会话。通常来说,一个页面只产生一个会话,之后所有该页面的请求都是基于该会话进行,关闭该页面即代表会话结束。这里一个页面产了多个会话显然是有问题的。
cookie如何维持会话状态
cookie会在每次请求时带入到请求头中,服务器可以通过相关接口读取cookie信息,每个客户端都有自己的cookie。当初次请求服务器时,cookie为空,服务器给它分配一个新的会话,并将会话通过Set-Cookie:JSESSIONID=EF8C88B741473AC36CE395668FCBB7B4写入到cookie。需要注意的是,这里的Set-Cookie并没有对cookie直接写入,而是将Set-Cookie作为响应头返回到客户端,客户端得到响应后读取Set-Cookie的内容,并将其写入本地cookie中。再次发送请求时,新写入的JSESSIONID会随着cookie一同提交到服务器,服务器根据JSESSIONID来查找会话。如果已经存在,则找到原来的会话,在该会话的基础上进行通信,否则就重新创建会话,并再次向客户返回Set-Cookie及JSESSIONID。如此重复上述过程,即为cookie维持会话状态的过程。
cookie设置失败的原因
具体到皓优企后台登录失败的情况中,服务端每次处理请求时都创建新的Session并向客户端发送了Set-Cookie。由此可以判断,客户端发送的请求中,Cookie的内容要么是不带JSESSIONID,要么是带的JSESSIONID在服务端已经失效。在Chrome开发者工具栏中,打开Application栏,可以看到Cookie的内容为空。也就是说,虽然服务端通过Set-Cookie返回了JSESSIONID,但客户端并没有将JSESSIONID写入到Cookie中。之后的所有请求都不带JSESSIONID,因此才会每次请求都产生新的会话。Set-Cookie是http协议的约定,为什么会设置失败呢?在Cookie的属性中,有一个domain属性,该属性记录了服务端域名。在皓优企后台页面中,cookie设置的domain域名为http://192.168.1.39:8001/dist/,而响应头中Set-Cookie的domain指向http://192.168.1.230:81/managment。两者不一致,造成了Set-Cookie无法写入本地Cookie,从而造成服务器每次请求都重新分配JSESSIONID,进而导致登录失败。
解决办法
打开Chrome浏览器,地址栏里输入:chrome://flags/
找到下面列表项目:
**1 .SameSite by default cookies,
- Cookies without SameSite must be secure**
将这两项设置成disabled,然后重启一下浏览器。再次登录,就能够成功登录,并且cookie中也成功写入了JSESSIONID。一切恢复正常!