微服务session落坑记

微服务session落坑记.jpg

本文适用于对session、cookie有一定了解的同学,主要以问题定位过程为线索,简单讲述tomcat session生成机制、oauth2认证过程以及spring方法参数映射处理等内容

背景知识

  • session:由于http协议无状态,为了保存用户状态信息,web容器支持session管理机制,当客户端请求web应用时,如果在处理过程中调用了request.getSession()方法,则web容器会先根据url或者cookie中上传的JSESSIONID(默认,可以另行设置,该值会被设置到request对象的requestedSessionId字段)查找对应session,如果获取不到将自动创建一个session对象;当session过期或被放弃后,服务器将终止该session
protected Session doGetSession(boolean create) {
// 略去部分代码
 (requestedSessionId != null) {
        session = manager.findSession(requestedSessionId);
        // 略去部分代码
        String sessionId = getRequestedSessionId();
        // 略去部分代码
        session = manager.createSession(sessionId);

        // 创建cookie并写入response
        if (session != null
                && context.getServletContext()
                        .getEffectiveSessionTrackingModes()
                        .contains(SessionTrackingMode.COOKIE)) {
            Cookie cookie =
                ApplicationSessionCookieConfig.createSessionCookie(
                        context, session.getIdInternal(), isSecure());

            response.addSessionCookieInternal(cookie);
        }
        // 略去部分代码
    }
  • cookie:为了服务器能够识别不同的客户端,客户端通过cookie保存服务端返回的数据(如JSESSIONID,tomcat服务器默认的session对应的cookie key为JSESSIONID),然后服务端通过客户端请求时放在http header中的cookie数据找到之前为客户端创建的session;cookie分为会话cookie和持久cookie,会话Cookie浏览器会话有效期间存在,持久cookie服务端会设置http header 缓存相关字段指示客户端缓存策略,cookie传到客户端后,保存在某个目录下
  • oauth2:oauth是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用,可以用于微服务环境下的公共鉴权,而本文服务鉴权走的就是oauth2

前人挖坑后人落,都是框架惹的祸

问题特征

  • 需求上线在即,发现某个接口请求后会新生成JSESSIONID并以Cookie形式回写浏览器,导致后续请求鉴权失败,必现
  • 服务相互调用关系比较复杂,需要在开发环境测试该功能,本地没有测试

问题定位过程:

  • 交流得知,此前定位过程中,将被请求方法体代码全部注销后,问题仍然存在,于是错过了查看问题代码(其实是方法参数出了问题),尽早定位出问题的好机会
  • 怀疑是否nginx会话保持策略导致的问题(但是该策略应该会对所有请求均产生影响,而不只是单个请求),查看nginx.conf配置,该服务没有走负载均衡
  • 怀疑是否nginx对该请求路径(路径中包含auth敏感字段)做了特殊配置,但查看配置,nginx对于该服务请求路径配置规则很简单,且将请求路径中auth字段删掉后测试,问题仍然存在
  • 怀疑是否有外围代码重写了cookie,搜索没找到相关代码
  • 梳理服务鉴权过程(见top图,图中做了缩略,将公共认证服务删除,直接对接oauth2),描述如下:
    1)认证鉴权逻辑被封装在了公共Filter中,对所有请求进行拦截,判断是否已登录
    2)如果没有上传JSESSIONID或者无法据其在redis找到session及token信息,返回客户端重定向到login接口
    3)客户端调用login接口:服务端调用oauth2(其实有个公共的鉴权服务)认证合法性,将认证返回的token信息融合自身的JSESSIONID写入redis,随后将服务端JSESSIONID写回客户端cookie,坑:此处复用了tomcat默认的JSESSIONID,推测是为了复用request的getRequestedSessionId方法,该方法会直接取客户端cookie提交的JSESSIONID,业务中多次用到了getRequestedSessionId方法,tomcat session和服务认证返回session除了都叫JSESSIONID外,没有半毛钱关系,但是因为重名,相互之间会覆写
    4)客户端带着认证返回的JSESSIONID继续调用之前的业务接口,通过认证,走业务逻辑,其实此时tomcat中的JSESSIONID和上传的JSESSIONID不一致,根据上传的JSESSIONID在tomcat是找不到对应session的
    5)认证过程还有其他逻辑,此处做了删减,不影响主体流程
  • 梳理之后,发现二者之间虽然key一致但是值不同,而且彼此会干扰,于是怀疑外围代码调用了getSession方法,搜索代码未找到
  • 查看请求路径对应方法,方法中使用了session参数,但是方法体中未使用该参数,联想到spring的参数值自动映射机制(见ServletRequestMethodArgumentResolver),在为session赋值的过程中调用了getSession方法,进而由于在tomcat找不到对应session而新建、回写相关cookie到客户端
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        Class<?> paramType = parameter.getParameterType();
        // 略去部分代码
        if (HttpSession.class.isAssignableFrom(paramType)) {
            HttpSession session = request.getSession();
        // 略去部分代码
        }
}
  • 删除参数,测试,问题解决

  • 使用该认证机制的服务的业务方法中不要使用tomcat的session机制(如getSession或session参数),否则就会出现这个问题

解决方案

  • 针对此问题,将session参数去掉
  • 将认证机制的JSESSIONID换成另外一个名字,但是改动量比较大,可能会有其他坑
  • 走分布式session解决方案,将tomcat的session管理机制和分布式session结合起来
  • 走jwt token处理机制,服务端不再存储token,仅做鉴权和刷新
欢迎关注我的微信公众号
68号小喇叭
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容

  • 目录Cookie机制什么是CookieCookie的不可跨域名性Unicode编码:保存中文BASE64编码:保存...
    Tomatoro阅读 16,908评论 7 186
  • 会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Se...
    chinariver阅读 5,586评论 1 49
  • 转自 :http://blog.csdn.net/taoff/articles/1921009.aspx 一、术语...
    stone_yao阅读 6,150评论 0 31
  • 此时的北京,微凉,走到阳光洒下的地方暖暖的,路过的居民楼旁边的大树,好听的麻雀声听得让人耳朵都痒痒的,还没有长...
    翻滚吧猫猫阅读 169评论 0 0
  • 逻辑后果不是惩罚,是为了让孩子停止不良行为而转移到其他的事情上,因此,如果不能确保孩子的感觉好,那就不要用逻辑后果...
    书媛jy阅读 313评论 0 1