原文鏈接:https://www.dubby.cn/detail.html?id=9109
隨著服務(wù)化的普及挨务,直接維護(hù)session的越來越困難谎柄,現(xiàn)在一般來說都會(huì)使用一個(gè)token來表示用戶的登錄狀態(tài)朝巫,用來標(biāo)識(shí)這個(gè)用戶的身份劈猿,這就是登錄態(tài)糙臼。
登錄態(tài)的解析一般就是入?yún)⑹莟oken变逃,而返回結(jié)果是userId的方法(或服務(wù)名眉、接口)损拢。
一般來說,登錄態(tài)校驗(yàn)的服務(wù)掏秩,QPS都會(huì)很大,因?yàn)榇蟛糠终埱蠖夹枰蕾囘@個(gè)校驗(yàn)結(jié)果來做自己的業(yè)務(wù)邏輯荆姆。所以如果保證登錄態(tài)解析的可靠性蒙幻,和低延時(shí)是相當(dāng)重要的。
這里我簡單描述下我所知道的幾種常見的實(shí)現(xiàn)方式胆筒。
1.存儲(chǔ)型
存儲(chǔ)型token邮破,就是根據(jù)token這個(gè)字符串,可以在服務(wù)端存儲(chǔ)上查到用戶信息仆救,那就是校驗(yàn)成功抒和,如果查不到,那就是校驗(yàn)失敗彤蔽。
對于QPS很低的應(yīng)用摧莽,可以使用MySQL來做存儲(chǔ),對于QPS很高的顿痪,可以使用Redis來做存儲(chǔ)范嘱。這個(gè)方案的優(yōu)勢是,簡單清晰员魏,易于實(shí)現(xiàn),且很自由叠聋,邏輯控制完全在服務(wù)端撕阎,比如踢誰下線、統(tǒng)計(jì)多少人登錄碌补,都一目了然虏束;缺點(diǎn)是,這個(gè)解析的強(qiáng)依賴于這個(gè)存儲(chǔ)厦章,存儲(chǔ)響應(yīng)慢镇匀,那解析延時(shí)就高,存儲(chǔ)可靠性低袜啃,那解析可靠性就不會(huì)高汗侵。雖說MySQL Cluster或者Redis Cluster已經(jīng)很可靠的,但網(wǎng)絡(luò)抖動(dòng),就真的無能為力了晰韵,網(wǎng)絡(luò)一抖发乔,解析就失敗或超時(shí)。
且雪猪,成本其實(shí)很高的栏尚,每個(gè)用戶的每次登陸,都需要在存儲(chǔ)中記錄一個(gè)數(shù)據(jù)只恨,如果是MySQL還好译仗,如果是Redis,那內(nèi)存成本其實(shí)不小官觅,感興趣的可以自己算下纵菌。
2.計(jì)算型
計(jì)算型token,就是把用戶信息如userId加密成一個(gè)字符串缰猴,這個(gè)字符串就是token产艾,那么每次解析其實(shí)就是解密,解密出明文滑绒,比如userId,generateTimestamp闷堡,那么再根據(jù)generateTimestamp判斷是否過期,如果解析都失敗了疑故,那就直接失敗杠览。
這個(gè)方案的優(yōu)點(diǎn)是,性能很好纵势,延時(shí)極低踱阿,且做到了真正的服務(wù)端無狀態(tài),不依賴任何外部存儲(chǔ)钦铁,單看服務(wù)的話软舌,可靠性幾乎是最高的;但是缺點(diǎn)也很明顯牛曹,完全依賴加密算法佛点,那如果被破解,就完蛋了黎比,這個(gè)可以考慮定期更換密鑰超营,但是登錄態(tài)信息完全放在客戶端,服務(wù)端對的登錄態(tài)的控制就很難了阅虫,比如踢誰下線演闭,統(tǒng)計(jì)登錄用戶幾乎不可能。
3.計(jì)算+存儲(chǔ)
考慮到計(jì)算和存儲(chǔ)的優(yōu)劣勢颓帝,我們可以考慮結(jié)合他們米碰。這里舉個(gè)例子token是個(gè)加密后的密文窝革,解密后可以分成好幾個(gè)字段,分別代表userId,generateTime,randomString见间。那么聊闯,如果解析都失敗了,那就直接失敗了米诉,如果解析成功了菱蔬,再根據(jù)generateTime來判斷是否過期,如果過期了史侣,那也直接失敗了拴泌,如果都通過了,在拿randomString去存儲(chǔ)中查詢惊橱,以Redis為例蚪腐,我們的存儲(chǔ)結(jié)構(gòu)可以設(shè)計(jì)成key是userId,value是sorted set税朴,其中每個(gè)元素就是randomString回季,查得到就是合法,查不到就是非法正林。
優(yōu)點(diǎn)是泡一,那么在極端情況下,如果Redis訪問失敗/超時(shí)觅廓,那也可以退回成純計(jì)算型token鼻忠,暫時(shí)不去校驗(yàn)randomString,等Redis恢復(fù)后繼續(xù)校驗(yàn)杈绸;缺點(diǎn)是帖蔓,實(shí)現(xiàn)復(fù)雜。
說到這里可靠性其實(shí)已經(jīng)很高了瞳脓,但延時(shí)呢塑娇?
4.長短token
這里借鑒了緩存的概念,當(dāng)然這里的緩存不是Redis劫侧。以PC為例钝吮,cookie里可以set兩個(gè),longToken,shortToken板辽,其中l(wèi)ongToken可以使用第三步說的計(jì)算+存儲(chǔ)來實(shí)現(xiàn),那么shortToken呢棘催?每次校驗(yàn)登錄態(tài)時(shí)劲弦,同時(shí)傳入longToken,shortToken,如果沒有shortToken醇坝,那么就去解析longToken邑跪,解析完之后如果成功次坡,就生成一個(gè)新的shortToken給客戶端;如果有shortToken画畅,那么就去解析shortToken砸琅,shortToken完全使用加密的方式,如果shortToken解析成功就算成功轴踱。
需要注意shortToken的有效期一定要合適症脂,這里的shortToken其實(shí)就是緩存,如果有效期合適的話淫僻,大部分請求都會(huì)由shortToken解析出來诱篷,避免了對存儲(chǔ)的網(wǎng)絡(luò)調(diào)用。如果有效期太長雳灵,會(huì)不安全棕所,且踢出某個(gè)用戶可能會(huì)有延時(shí)才能生效,有效期如果太短的話悯辙,那緩存效果可能不明顯琳省,所以需要結(jié)合業(yè)務(wù)特性來做決定。