看过我以前博客的同窗会知道,19年我参与了一个中台项目,该项目是咱们公司和其余几大行业内知名公司一块儿协力作的(感受个人描述有装数字的嫌疑)。由于须要对接多方外部系统,这致使了咱们除了须要维护内部的开发环境、内部测试环境、正式生产环境以外,还须要维护一套公共的外部测试环境。前端
各个环境部署的状况是:java
一、开发环境:部署在公司内部服务器上;web
二、内部测试环境:部署在阿里云上;docker
三、外部测试环境:部署在腾讯云上;数据库
四、正式生产环境:部署在腾讯云上;数组
这是背景交代。服务器
最近我在给咱们的web端增长权限控制(就是不给钱我就不给你看,给钱给的少了,我只给你看不给你改,给钱给够了爱咋改咋改,就是这么实在)。因为咱们前端用的是咱们公司内部自主开发的前端解决方案,权限控制部分在底层代码里就已经实现了,我须要作的就是:把我要设置的权限脚本在须要插入的数据库里跑一遍,经过接口取出登录用户所拥有的权限数据,而后根据已有规则进行判断便可。这个过程看起来和实现都很简单,惟一稍微复杂一点的地方可能就是:权限的数据存在其余系统的数据库中,这也就意味着,咱们须要对接外部系统,经过和他们制定统一的规则,发送rest请求去获取所需的数据。这个过程其实也很简单,就是须要构造一个请求头部,而后根据既定规则生成url便可。运维
不过这部分的后台代码以前小伙伴因为写别的模块需求已经实现了,能够躺在树下吃枣这件事我是最开心的啦(可我才不会嗦出来~~)。前端代码一鼓作气,写的感受手超级顺,当时老开心了,追着测试后面催人家赶忙测(以前每天被他们催着改bug,可不得在他们忙的时候给添点乱咋的)。等测试回过神有时间开始测个人单子的时候,他告诉我-内部测试环境和外部测试环境都gg了,显示为无权限,不管当前的用户是否有设置权限,甚至是超级管理员(超级管理员默认拥有全部的权限)。maven
这样我就不服气了,不过环境既然挂了,并且看着也确实是个人缘由,那不服也得找到缘由并修复掉(毕竟是一个有原则的职场人)。post
找了一圈,发现是对外部系统的配置,没有加到内部测试环境和外部测试环境,而我构造的url及请求头部验证 的内容都与配置息息相关,因此在测试环境,实际向外部的请求根本未成功发出过(说到这个,我其实不是很理解,为啥测试环境须要运维手动添加配置信息,而咱们本地都是直接某我的写在yml配置文件中便可)。emmm,果断让运维大佬帮忙加了一下,心想这下总在没有问题了吧。
而后费劲八擦终于配置都加好了,环境也更新好了以后,发现外部测试环境正常了,而后内部测试环境依旧gg。这就让人很费解了,讲道理代码是同一套,没道理一个能够一个不能够呀。找他们的区别,想了半天也只有多是内部测试环境的配置没有加上,而后我在代码里打了一堆的日志,发现都是能正常取出配置信息的,可是内部测试环境依旧挂着的,而后我担忧我理解的有误,依旧怀疑是运维没有配好,拉着运维让他给我看了docker镜像内容,好吧,确实是有配置的。那问题就不知道在哪里了呀?!!!不得已找了大神,大神告诉我,我加的权限在他本地也是一直在报错(报错500,和内部测试环境日志中打印出来的一致)....嗯????难道只有个人本地开发环境是正常的?赶忙找了周围的几个小伙伴试试,本地都是正常的,这我就放心了~~那么,问题来了,为啥大神的本地在报错?这个时候,正常的思路确定是找不一样呀~~
我和大神最大的不一样就是,我是在公司总部上班,而他是在公司在外地的办事处上班(可是咱们是一个项目组的,结构就是如此神奇)。这个时候,大神一拍脑门:不会是内部测试环境给大家总部的网关和腾讯云配了白名单吧(总部是能理解的啦,至于腾讯云,大概是由于腾讯是金主爸爸?)。找运维确认了下,还真的是!那么这里有有一个问题呀,就算没有开白名单,对外部系统的访问也是构造了请求头和url,走正常的rest请求的流程也应该是能正常带回来数据的,而不该该是报错500(HTTP500是服务器错误,具体缘由请自行百度)。大神说:来,我们一步一步来,先用postman模拟下实际向外发送的请求,看看是否正常。而后大神发现,用根据个人规则生成的请求头部和url,一直会报500,大神表示受不了了,他要找对接系统的开发人员看看了。对方人员看了一眼:你这个authorization咋看着怪怪的?他甩了一个根据他们的规则生成的authorization出来,看着也确实是比较符合一般的验证字段结构。对照了下代码,发现两边的代码结构基本是同样的,代码贴出以下:
//咱们系统头部验证的构造
private HttpHeaders defaultHttpHeaders() { ... String authorization = "Basic " + Base64Utils.encode((username + ":" + password).getBytes()); ....
}
//对方系统头部验证的构造 private HttpHeaders defaultHttpHeaders() { ... String authorization = "Basic " + new String(Base64.encodeBase64((username + ":" + password).getBytes())); .... }
咱们构造的头部验证惟一的区别就在于,咱们用了Base64Utils默认的 toString()方法,而对方则是new了一个新的String对象。
在个人方法中,是将Base64编码后的结果以字节数组的的方式和前面的字符串常量进行拼接,这个过程当中,字节数组将会被 java 自带的 toString()方法转化为 string 类型,toString() 方法源码以下:
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
所以,我构造出的 authorization 长这样:
而对方使用的是 new String() 方法,即将字节数组直接转化为一个新的字符串,转换的源码以下:
public String(byte bytes[]) { this(bytes, 0, bytes.length); }
public String(byte bytes[], int offset, int length) {
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(bytes, offset, length);
}
对方构造的 authorization 长这样:
从以上源码能够看出,对方是生成一个新的 string 变量,再将根据既定规则构造的内容进行 base64 编码解码加密的过程,而咱们用到的 toString() 方法,能够理解为返回一个"由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成"的字符串。就算不理解前面的balabala描述,也已经知道,咱们的 authorization 的构成不知足意义上 认证的需求。
问题找到了,那就赶忙修复卡~~(看着晚上能够早点回家坐在餐桌旁边次饭饭,开森)
然而,有句老话叫“乐极生悲”,老人说的话每每有他的道理....
在我修复认证的构造过程当中,项目组的小哥哥发了个版本(就是好比咱们本来开发环境是 0.0.1-SNAPSHOT 快照版本,在发了版本以后,生产环境为 0.0.1 版本,而咱们开发环境版本 +1 变成 0.0.2-SNAPSHOT 版本)。然而,我并无关注到这件事,依旧在提交代码以后开开心心的在 jenkins上启动 job 编译更新咱们的内部测试环境验证。满怀激动的等着 job 的进度条到达100%,打开测试环境狂刷。然而。。。内部测试环境宛如米有提交任何代码。我都怀疑是否是由于我打开测试环境太快了,实际测试环境并无彻底更新部署完成。默默等待了 10 min(别问我为啥是10分钟,经验告诉个人时长),满怀忐忑的验证,果真依旧挂着。又到了百思不得其解的时候,正确的解决方式是啥?固然是抱大神大腿啊。大神在本地验证,一块儿正常,而后咱们俩在电话里相互看着电脑屏幕无言,沉默良久,大神忽然一拍脑门(他的老习惯)说:会不会是 部署的版本号没有调整啊?想一想都以为有可能。这就又到了运维大佬出场的时候了,磨着运维小哥哥进入docker 仓库,查看个人操做记录是否是成功了,以及操做的实际版本号。果真~~眼泪流下来(实际部署的版本号是咱们开发看不到的,只有运维能够控制)。
眼睁睁看着运维小哥哥修改好了版本号以后,再磨着他编译部署了一遍内部测试环境(毕竟咱们是看不到实际是否是部署成功了啊,我就是磨人的小妖精)。怀着宛如第一次见本身亲儿子的老父亲那种心情,颤抖着小手手打开内部测试环境,哇,好了啊,哇,能够回家吃饭饭了啊,哇,好开心啊(其实此刻在写文的我一点都不开心,由于我心心念念的寒天又被放进了别人的杯子,以前在厦门喝到寒天爱玉超级爱的,回上海以后发现也有,满怀期待的点了两次。。。两次啊,每一次都被放进了别人的杯子!!!)
此部分我后面还会增长 “maven版本管理”相关的内容,先立好flag。