美文网首页
记录今日一问题排查(认证失效或授权码错误问题)

记录今日一问题排查(认证失效或授权码错误问题)

作者: Chris_a619 | 来源:发表于2019-11-26 23:21 被阅读0次

    记录今日一问题排查(认证失效或授权码错误问题)

    今日得一BUG:在统一认证(shrio)的环境下,系统A调用系统B时出现失效/授权码错误的问题。

    排查思路:

    1.先看浏览器/后台报错信息。

    可以看到错误的描述为:错误的授权码。

    该信息由统一认证系统返回,根据此描述,可以在统一认证系统中全文搜索到报错代码出处。

    进入此条件的途径为baseOauthService.checkAuthCode(authCode)==false

    checkAuthCode方法为shrio包中的方法。反编译相关代码。

    故大方向上,有两种可能,X:this.cache.get(authCode)==null  Y:前端传过来的code是错乱的code

    先开始X方向:

    那么问题点就在cache。反编译,看看所有cache和code相关的操作

    很明显,在登录成功的时候会addAuthCode,将code值,和username存入cache中。其中username来自SecurityUtils.getSubject().getPrincipal()。

    那么将有3种情况会让chche去GET时返回null:

    A. username==null.即SecurityUtils.getSubject().getPrincipal()==null,则本身存储时,存在cache里面的就是code,null

    B.有地方调用了removeAuthcode方法,或者使用了put.(code,null)的操作将该code置空

    C.cache中由于某种原因,该code,username的值没有了

    从A情况来看。继续反编译getPrincipal()方法;

    根据上面的代码可以看出,如果是Null,很可能是2种情况。session是null,所以返回null,导致最后返回null;或者runAsPrincipals的第一个元素是null。经排查getSession方法,发现session不会为null。那么可能是List第一个元素为Null。

    很可能联想到一个常见问题,是否List在多线程高并发下,add失败,造成null值。

    那么我们找到对应增加Attribute的地方。代码如下:

    果然apache的项目应该不会犯这种错,shrio源代码使用了CopyOnWriteArrayList(常见的解决多线程下list并发安全问题的方法之一,增删改加锁,读不加锁,读写分离),那么也不存在线程安全问题。故排除。

    B情况也搜了下,除了SSO注销会使用logout,会调用remove方法,其他没有途径主动Remove code

    C情况太灵异,没有多想。

    则思路转变到大思路中X / Y中的Y思路来,即前端由于某种原因,发生了错乱,传错了没有的code值。

    首先code存于cookie中。要么cookie值没了,要么code错乱了。

    如果是cookie值没了,可能是写cookie时的expire问题。查阅代码,发现后端使用了maxAge属性定义cookie时长(正数,负数,0,具体查阅相关HTTP协议),发现该属性是HTTP1.1新增,而HTTP1.0使用老的expire方法,一般来说会向下兼容,则expire在1.0和1.1应该都没有问题(expire有问题,依赖于客户端时间)。如果用maxAge,那么HTTP1.0的浏览器会不会有问题。但是经过沟通,发现出问题的机器用的浏览器,是HTTP1.1。那么这条路也断了。

    不是cookie值没了,那么可能是code错乱了。很有可能是前端的某些操作会使session错乱。经查询,使用iframe,frameset等,会造成session错乱或者丢失的问题。项目中Ext.js用到iframe的部分和前端人员沟通,有报表。结果发现出问题的系统,经测试,报表操作不会引起该问题。此路也断。

    重点来了,吃了几个面包以后,感觉思路变得清晰起来,想起来还有X思路中的C情况没有仔细考虑。

    又回归到C中来。Cache中的code没了?

    回归到管理session以及code的相关配置策略中来。session时长都是已经设置过的。那么可能是管理的相关策略。

    使用了ehcache进行管理。

    默认策略如下

    具体的authcode如下

    正常情况继承默认defaultCache,默认的时间为2分钟,但是如果又自己定义了具体名称的chache,则按自己定义的时间计算,例如code-cache。

    具体相关配置含义可以查询相关文档。可以发现timeToIdleSeconds为36000秒,即600分钟。堆内存中最大缓存数对象为400。如果超过400会发生什么,可以看到默认配置策略中memoryStoreEvictionPolicy="LRU"(最近最少使用)。FIFO(先进先出),LFU(较少使用)。

    那么很可能让code为null的情况是,超出了400个缓存数的code,则让最少用的那个code没了。并且子节点中配置 了overflowToDisk="false",则多出的缓存数并不会保存到磁盘。

    又结合系统中对code的处理,我们发现只有从统一认证系统注销,才会清除code。而关闭浏览器其实并不会清除code,部分系统记住密码功能有问题的,关闭浏览器以后再登录系统,甚至还会再申请一个code,所以code会积累。

    综上所述,如果600分钟内,各个系统的操作,除去主动注销的部分,600分钟内积累的缓存数超过400,则很可能少用的code将会丢失。所以也可以预计到,在高峰期出现失效的问题概率会较高,夜晚则很少。同时换个思路,可以用cache的属性去做一些限制登录控制流量的功能。

    建议解决办法:增加最大缓存数,同时code时间最好也和各个系统同步。并且有关cookie相关的内容需要子系统统一考虑,例如使用localStorage,sessionStorgae。

    所以任何问题的出现都是有原因的,通过一步步排查,总能找到问题的根源。

    相关文章

      网友评论

          本文标题:记录今日一问题排查(认证失效或授权码错误问题)

          本文链接:https://www.haomeiwen.com/subject/jnxuwctx.html