微服務(wù)session落坑記

微服務(wù)session落坑記.jpg

本文適用于對session、cookie有一定了解的同學(xué)驾霜,主要以問題定位過程為線索案训,簡單講述tomcat session生成機(jī)制、oauth2認(rèn)證過程以及spring方法參數(shù)映射處理等內(nèi)容

背景知識

  • session:由于http協(xié)議無狀態(tài)粪糙,為了保存用戶狀態(tài)信息强霎,web容器支持session管理機(jī)制,當(dāng)客戶端請求web應(yīng)用時(shí)蓉冈,如果在處理過程中調(diào)用了request.getSession()方法城舞,則web容器會先根據(jù)url或者cookie中上傳的JSESSIONID(默認(rèn),可以另行設(shè)置寞酿,該值會被設(shè)置到request對象的requestedSessionId字段)查找對應(yīng)session家夺,如果獲取不到將自動創(chuàng)建一個(gè)session對象;當(dāng)session過期或被放棄后伐弹,服務(wù)器將終止該session
protected Session doGetSession(boolean create) {
// 略去部分代碼
 (requestedSessionId != null) {
        session = manager.findSession(requestedSessionId);
        // 略去部分代碼
        String sessionId = getRequestedSessionId();
        // 略去部分代碼
        session = manager.createSession(sessionId);

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

            response.addSessionCookieInternal(cookie);
        }
        // 略去部分代碼
    }
  • cookie:為了服務(wù)器能夠識別不同的客戶端拉馋,客戶端通過cookie保存服務(wù)端返回的數(shù)據(jù)(如JSESSIONID,tomcat服務(wù)器默認(rèn)的session對應(yīng)的cookie key為JSESSIONID)惨好,然后服務(wù)端通過客戶端請求時(shí)放在http header中的cookie數(shù)據(jù)找到之前為客戶端創(chuàng)建的session煌茴;cookie分為會話cookie和持久cookie,會話Cookie瀏覽器會話有效期間存在日川,持久cookie服務(wù)端會設(shè)置http header 緩存相關(guān)字段指示客戶端緩存策略景馁,cookie傳到客戶端后,保存在某個(gè)目錄下
  • oauth2:oauth是一個(gè)開放標(biāo)準(zhǔn)逗鸣,允許用戶讓第三方應(yīng)用訪問該用戶在某一網(wǎng)站上存儲的私密的資源(如照片合住,視頻,聯(lián)系人列表)撒璧,而無需將用戶名和密碼提供給第三方應(yīng)用透葛,可以用于微服務(wù)環(huán)境下的公共鑒權(quán),而本文服務(wù)鑒權(quán)走的就是oauth2

前人挖坑后人落卿樱,都是框架惹的禍

問題特征

  • 需求上線在即僚害,發(fā)現(xiàn)某個(gè)接口請求后會新生成JSESSIONID并以Cookie形式回寫瀏覽器,導(dǎo)致后續(xù)請求鑒權(quán)失敗繁调,必現(xiàn)
  • 服務(wù)相互調(diào)用關(guān)系比較復(fù)雜萨蚕,需要在開發(fā)環(huán)境測試該功能,本地沒有測試

問題定位過程:

  • 交流得知蹄胰,此前定位過程中岳遥,將被請求方法體代碼全部注銷后,問題仍然存在裕寨,于是錯過了查看問題代碼(其實(shí)是方法參數(shù)出了問題)浩蓉,盡早定位出問題的好機(jī)會
  • 懷疑是否nginx會話保持策略導(dǎo)致的問題(但是該策略應(yīng)該會對所有請求均產(chǎn)生影響派继,而不只是單個(gè)請求),查看nginx.conf配置捻艳,該服務(wù)沒有走負(fù)載均衡
  • 懷疑是否nginx對該請求路徑(路徑中包含auth敏感字段)做了特殊配置驾窟,但查看配置,nginx對于該服務(wù)請求路徑配置規(guī)則很簡單认轨,且將請求路徑中auth字段刪掉后測試绅络,問題仍然存在
  • 懷疑是否有外圍代碼重寫了cookie,搜索沒找到相關(guān)代碼
  • 梳理服務(wù)鑒權(quán)過程(見top圖嘁字,圖中做了縮略昨稼,將公共認(rèn)證服務(wù)刪除,直接對接oauth2)拳锚,描述如下:
    1)認(rèn)證鑒權(quán)邏輯被封裝在了公共Filter中,對所有請求進(jìn)行攔截寻行,判斷是否已登錄
    2)如果沒有上傳JSESSIONID或者無法據(jù)其在redis找到session及token信息霍掺,返回客戶端重定向到login接口
    3)客戶端調(diào)用login接口:服務(wù)端調(diào)用oauth2(其實(shí)有個(gè)公共的鑒權(quán)服務(wù))認(rèn)證合法性,將認(rèn)證返回的token信息融合自身的JSESSIONID寫入redis拌蜘,隨后將服務(wù)端JSESSIONID寫回客戶端cookie杆烁,坑:此處復(fù)用了tomcat默認(rèn)的JSESSIONID,推測是為了復(fù)用request的getRequestedSessionId方法简卧,該方法會直接取客戶端cookie提交的JSESSIONID兔魂,業(yè)務(wù)中多次用到了getRequestedSessionId方法,tomcat session和服務(wù)認(rèn)證返回session除了都叫JSESSIONID外举娩,沒有半毛錢關(guān)系析校,但是因?yàn)橹孛嗷ブg會覆寫
    4)客戶端帶著認(rèn)證返回的JSESSIONID繼續(xù)調(diào)用之前的業(yè)務(wù)接口铜涉,通過認(rèn)證智玻,走業(yè)務(wù)邏輯,其實(shí)此時(shí)tomcat中的JSESSIONID和上傳的JSESSIONID不一致芙代,根據(jù)上傳的JSESSIONID在tomcat是找不到對應(yīng)session的
    5)認(rèn)證過程還有其他邏輯吊奢,此處做了刪減,不影響主體流程
  • 梳理之后纹烹,發(fā)現(xiàn)二者之間雖然key一致但是值不同页滚,而且彼此會干擾,于是懷疑外圍代碼調(diào)用了getSession方法铺呵,搜索代碼未找到
  • 查看請求路徑對應(yīng)方法裹驰,方法中使用了session參數(shù),但是方法體中未使用該參數(shù)片挂,聯(lián)想到spring的參數(shù)值自動映射機(jī)制(見ServletRequestMethodArgumentResolver)邦马,在為session賦值的過程中調(diào)用了getSession方法,進(jìn)而由于在tomcat找不到對應(yīng)session而新建、回寫相關(guān)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();
        // 略去部分代碼
        }
}
  • 刪除參數(shù)滋将,測試邻悬,問題解決

  • 使用該認(rèn)證機(jī)制的服務(wù)的業(yè)務(wù)方法中不要使用tomcat的session機(jī)制(如getSession或session參數(shù)),否則就會出現(xiàn)這個(gè)問題

解決方案

  • 針對此問題随闽,將session參數(shù)去掉
  • 將認(rèn)證機(jī)制的JSESSIONID換成另外一個(gè)名字父丰,但是改動量比較大,可能會有其他坑
  • 走分布式session解決方案掘宪,將tomcat的session管理機(jī)制和分布式session結(jié)合起來
  • 走jwt token處理機(jī)制蛾扇,服務(wù)端不再存儲token,僅做鑒權(quán)和刷新
歡迎關(guān)注我的微信公眾號
68號小喇叭
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末魏滚,一起剝皮案震驚了整個(gè)濱河市镀首,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鼠次,老刑警劉巖更哄,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異腥寇,居然都是意外死亡成翩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門赦役,熙熙樓的掌柜王于貴愁眉苦臉地迎上來麻敌,“玉大人,你說我怎么就攤上這事掂摔∈醺幔” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵乙漓,是天一觀的道長聂示。 經(jīng)常有香客問我,道長簇秒,這世上最難降的妖魔是什么鱼喉? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮趋观,結(jié)果婚禮上扛禽,老公的妹妹穿的比我還像新娘。我一直安慰自己皱坛,他們只是感情好编曼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著剩辟,像睡著了一般掐场。 火紅的嫁衣襯著肌膚如雪往扔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天熊户,我揣著相機(jī)與錄音萍膛,去河邊找鬼。 笑死嚷堡,一個(gè)胖子當(dāng)著我的面吹牛蝗罗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蝌戒,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼串塑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了北苟?” 一聲冷哼從身側(cè)響起桩匪,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎友鼻,沒想到半個(gè)月后傻昙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桃移,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了葛碧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片借杰。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖进泼,靈堂內(nèi)的尸體忽然破棺而出蔗衡,到底是詐尸還是另有隱情,我是刑警寧澤乳绕,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布绞惦,位于F島的核電站,受9級特大地震影響洋措,放射性物質(zhì)發(fā)生泄漏济蝉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一菠发、第九天 我趴在偏房一處隱蔽的房頂上張望王滤。 院中可真熱鬧,春花似錦滓鸠、人聲如沸雁乡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽踱稍。三九已至曲饱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間珠月,已是汗流浹背扩淀。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留桥温,地道東北人引矩。 一個(gè)月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像侵浸,于是被迫代替她去往敵國和親旺韭。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 目錄Cookie機(jī)制什么是CookieCookie的不可跨域名性Unicode編碼:保存中文BASE64編碼:保存...
    Tomatoro閱讀 16,946評論 7 186
  • 會話(Session)跟蹤是Web程序中常用的技術(shù)掏觉,用來跟蹤用戶的整個(gè)會話区端。常用的會話跟蹤技術(shù)是Cookie與Se...
    chinariver閱讀 5,620評論 1 49
  • 轉(zhuǎn)自 :http://blog.csdn.net/taoff/articles/1921009.aspx 一、術(shù)語...
    stone_yao閱讀 6,189評論 0 31
  • 此時(shí)的北京澳腹,微涼织盼,走到陽光灑下的地方暖暖的,路過的居民樓旁邊的大樹酱塔,好聽的麻雀聲聽得讓人耳朵都癢癢的沥邻,還沒有長...
    翻滾吧貓貓閱讀 174評論 0 0
  • 邏輯后果不是懲罰,是為了讓孩子停止不良行為而轉(zhuǎn)移到其他的事情上羊娃,因此唐全,如果不能確保孩子的感覺好,那就不要用邏輯后果...
    書媛jy閱讀 318評論 0 1