解决cookie无法写入的问题
文章目录
- 1 问题分析
- 2 跟踪CookieUtils
- 3 解决host地址的变化
- 4 网关的反向代理
- 5 Host写入问题
- 5.1 网关写入Host
- 5.2 敏感头过滤导致cookie没有写入
- 5.3 防止过滤器过滤Host
接上一篇鉴权微服务中间留下的问题,专门来分析解决一下这个问题,首先我们登录,然后查看cookie:
却发现cookie中空空如也,这是为什么?
1 问题分析
我们在之前测试时,清晰的看到了响应头中,有Set-Cookie属性
为什么在这里却什么都没有?
我们之前在讲cors跨域时,讲到过跨域请求cookie生效的条件:
- 服务的响应头中需要携带Access-Control-Allow-Credentials并且为true。
- 响应头中的Access-Control-Allow-Origin一定不能为*,必须是指定的域名
- 浏览器发起ajax需要指定withCredentials 为true
看看我们的服务端cors配置:
没有任何问题。
我们再来仔细看一下区别:调试的时候访问的是
http://localhost:8087/login,但是浏览器访问的却是
http://api.leyou.com/api/auth/ogin,那我们再用这个地址调试一次:
现在我们找到问题了!——路径问题!
但是路径变化会引起什么变化呢?——网关问题或者nginx问题二者都有可能产生问题,要逐一排查
2 跟踪CookieUtils
除了上面那两个原因,其次我们想,写cookie这个代码有没有问题,为什么刚才有现在又没有了呢?我们写cookie使用的是工具类:
CookieUtils,先看一下可以正常生成的cookie信息:
返回header:
LY_TOKEN=eyJhbGciOiJSUzI1NiJ9.eyJpZCI6MzIsInVzZXJuYW1lIjoiZGlhbmVtYXgiLCJleHAiOjE1NTUzMzE2MjF9.cYjoy_DaqlYx5GumxU7TExtENS1KBvNg_Sjdo1PBcW_tjYBu1xXtWfkwQV1_y03ttDcvs0PF3fQWkJOkmICv3n8Dy0do_M6KMMjG7fcNW-Mmk2blunOhw69o9ZSx0W0MSNGVMjR38OLyi9OumG3FzX2XjRB6GO_veBwMB5cmU; Domain=localhost; Path=/;HttpOnly
我们发现cookie的
domain属性似乎不太对。我们去Debug跟踪CookieUtils,看看到底是怎么回事:
- 我们发现内部有一个方法,用来获取Domain,先通过request.getRequestURL()方法来获取请求路径
- 我们设置断点,在产生token的 cookieUtils中的build()函数设置断点,单步执行
- 执行到setDomain,首先由request.getRequestURL()获取请求路径
- 此时发现请求路径被改变了,发现URL从
http://www.leyou.com/
变成了serverNamehttp://127.0.0.1:8087/login
- 之后经过一些截取操作,serverName变成了0.0.1,
- 但如果是
api.leyou.com
的话,最终就变成了leyou.com
,而leyou.com
是所有相关网站的共同后缀,可以供leyou所有网站来访问,这就很完美
- 那原因是什么呢?——serverName的问题
serverName是http://127.0.0.1:8087/login
,所以不管怎么截取都是有问题的 - 问题找到了:
我们请求时的serverName明明是:api.leyou.com,现在却被变成了:127.0.0.1,因此计算domain是错误的,cookie也是有domain(域)
的限制,一个网页,只能操作当前域名下的cookie,但是现在我们看到的地址是0.0.1,而页面是www.leyou.com,域名不匹配,cookie设置肯定失败了!
3 解决host地址的变化
那么问题来了:为什么我们这里的请求serverName变成了:127.0.0.1:8087呢?
这里的serverName其实就是请求的时的主机名:Host,serverName没问题,后续的自然会没问题,之所以改变,原因就是反向代理:当访问leyou域名时,这个域名指向了虚拟机
我们打开
nginx.conf,查看配置:
要想解决这件事,首先要知道
request.getRequestURLtomcat是怎么拿到域名地址的?
首先在浏览器F12控制台 随便打开一个js请求
可以发现Request URL:
http://www.leyou.com/plugins/jquery/jquery.min.js
上述URL在request中其实被分成了几段来表示:
- Host:www.leyou.com——host
- GET /js/plugins/jquery/jquery.min.js HTTP/1.1——路径和协议
全路径其实就是请求 host+端口(默认是80)+路径 拼在一起得到的 ,影响我们得到域名的原因就是Host ,后面的路径我们不关心! host其实是请求头的一部分,当我们反向代理的时候,nginx已经将请求头Host转换成了
192.168.124.1,于是在nginx反向代理时多设置一个Host头。
将nginx的conf文件修改,添加:
proxy_set_header Host $host
$host代表的是上一次原生请求的host,原生的请求一定是
api.leyou.com,它会读取原生请求的host放到$host的位置,变成
proxy_set_header Host api.leyou.com
到此为止,重启nginx
nginx -s reload
再次测试:
还是有问题。。。
4 网关的反向代理
其实刚才的问题没有找全,nginx把请求路径代理到了
htto://192.168.124.1:10010,但是我们拿到的serverName还是
http://127.0.0.1:8087,怎么从10010端口变成了8087端口呢,因此这不光是nginx的问题,网关也做了一次反向代理
因为网关是不能自己处理的,他会把请求转发到微服务8087来进行处理,现在我们把网关用debug启动,在网关中有很多过滤器,这些过滤器默认继承自
ZuulFilter,在其中一个
PreDecorationFilter的run方法打个断点,查询host,调用方法
ctx.getRequest().getHeader("host"):
发现此时的host是
api.leyou.com是正确的,说明我们nginx的配置生效了,理论上此时放行,是不会出现错误的,如果此时出现错误,那就是网关没有将host写进去
5 Host写入问题
5.1 网关写入Host
事实上,到此为止并没有将host写进去,原因是有个if判断 ——
porperties.isAddHostHeader(),成立才将host写入,点进方法发现
AddHostHeader是一个
boolean值,值为
false,属于
ZuulProperties,前缀是
zuul,修改这个值很简单:
继续debug运行看看有没有写入成功:
可以看到domain写入成功了,那我们来测试一下:
发现,响应头中还是没有
set-cookie!事实上到这里还没有结束,单单设置这个是不行的
5.2 敏感头过滤导致cookie没有写入
过滤器中还有一个
addIgnoredHeaders方法,会对一些头进行忽略,会对敏感头进行过滤
会发现,这里会通过一个属性为
SensitiveHeaders的属性,来获取敏感头列表,然后添加到
IgnoredHeaders中,这些头信息就会被忽略。
而这个
SensitiveHeaders的默认值就包含了
set-cookie:
现在set-cookie被滤掉,因此问题和原因我们知道了,但是先不管,我们先来看Host可不可以正常传递,debug发现Host还是没有被拿到!!!
5.3 防止过滤器过滤Host
ZuulFilter下面还有一个叫
RibbonRoutingFilter的过滤器,做负载均衡路由的方法
它有一个构建上下文的方法:
在构建上下文中会先获取头信息:
然后对头做一些判断:
判断方法:
如果是被允许的头信息,才会将其添加到Headers中去,如果头是被忽略的,则不会被添加,但是下面有一个switch语句,如果name是host,则忽略!因此host永远不会被添加进去
最后:尽管yml中设置了true,Host被添加进去了,但是由于这个过滤器,又被忽略掉了。因此无论如何我们都没办法把Host添加进去,这是一个bug
解决办法:
对比了上一个SpringCloud版本的源码,发现是没有if判断的,说明是因为加了这一段导致错误,因此我们修改一下版本
再次测试:
Host终于被添加进来了!此时再次debug程序,可以看到已经拿到了正确的domain:
6 Zuul的敏感头过滤
我们已经在前面5.2部分分析了cookie没有被写入的原因,我们现在来解决它:
解决方案有两种:
全局设置:
zuul.sensitive-headers=
指定路由设置:
zuul.routes.<routeName>.sensitive-headers=
zuul.routes.<routeName>.custom-sensitive-headers=true
思路都是把敏感头设置为null
现在再来测试一次:
一切正常,到此位置,cookie的写入问题被完美解决了
- 解决cookie在本地无法写入的办法
- “无法解析外部符号 __security_cookie”问题解决
- Asp.Net中Response.Cookies.Remove 无法删除COOKIE的问题解决方法
- ATS线上报告个别日志过大无法写入问题的解决方法
- “无法解析外部符号 __security_cookie”问题解决
- 解决刷入4.4.2之后外置SD卡 无法写入问题
- Servlet写入Cookie转发后无法读取的问题
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- 解决保存快照失败后redis无法写入的问题( Redis is configured to save RDB snapshots)
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- 解决vue跨域请求无法携带cookie,进而无法在服务器端设置session保持数据(状态)的问题
- 开机的时候如果出现提示$home/.dmrc无法写入 问题解决方法
- 安装Tomcat时候提示因无法写入服务而导致无法安装问题的解决方法
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- IE10、IE11 User-Agent 导致的 ASP.Net 网站无法写入Cookie 问题
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题和在在原文件后写入文件
- 解决新浪SAE无法写入jssdk.php的问题
- IE10、IE11 User-Agent 导致的 ASP.Net 网站无法写入Cookie 问题
- 使用nginx反向代理 cookie 无法写入问题
- 访问Samba服务器共享文件夹时无法写入问题的解决办法