【知識(shí)】JWT數(shù)據(jù)格式及實(shí)現(xiàn)單點(diǎn)登錄原理

1. 摘要

本文講解JWT(JSON Web Token )的定義,機(jī)制猾浦,格式和在跨域多網(wǎng)站單點(diǎn)登錄中的應(yīng)用为迈。

2.內(nèi)容

2.1 什么是JWT ?

Json web token(JWT)是為了網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開(kāi)發(fā)標(biāo)準(zhǔn)(RFC 7519),該token被設(shè)計(jì)為緊湊且安全的,特別適用于分布式站點(diǎn)的單點(diǎn)登陸(SSO)場(chǎng)景铛纬。JWT的聲明一般被用來(lái)在身份提供者和服務(wù)提供者間傳遞被認(rèn)證的用戶身份信息,以便于從資源服務(wù)器獲取資源唬滑,也可以增加一些額外的其它業(yè)務(wù)邏輯所必須的聲明信息告唆,該token也可直接被用于認(rèn)證,也可被加密间雀。

通俗來(lái)講悔详,JWT是一個(gè)含簽名并攜帶用戶相關(guān)信息的加密串,頁(yè)面請(qǐng)求校驗(yàn)登錄接口時(shí)惹挟,請(qǐng)求頭中攜帶JWT串到后端服務(wù)茄螃,后端通過(guò)簽名加密串匹配校驗(yàn),保證信息未被篡改连锯。校驗(yàn)通過(guò)則認(rèn)為是可靠的請(qǐng)求归苍,將正常返回?cái)?shù)據(jù)。

什么情況下使用JWT比較適合运怖?

  • 授權(quán):
    這是最常見(jiàn)的使用場(chǎng)景拼弃,解決單點(diǎn)登錄問(wèn)題。因?yàn)镴WT使用起來(lái)輕便摇展,開(kāi)銷小吻氧,服務(wù)端不用記錄用戶狀態(tài)信息(無(wú)狀態(tài)),所以使用比較廣泛咏连;
  • 信息交換:
    JWT是在各個(gè)服務(wù)之間安全傳輸信息的好方法盯孙。因?yàn)镴WT可以簽名,例如祟滴,使用公鑰/私鑰對(duì)兒 - 可以確定請(qǐng)求方是合法的振惰。此外,由于使用標(biāo)頭和有效負(fù)載計(jì)算簽名垄懂,還可以驗(yàn)證內(nèi)容是否未被篡改骑晶。

2.2 JWT 的數(shù)據(jù)結(jié)構(gòu)

2.2.1 傳統(tǒng) session 認(rèn)證及其弊病

互聯(lián)網(wǎng)服務(wù)離不開(kāi)用戶認(rèn)證痛垛。一般流程是下面這樣。

1桶蛔、用戶向服務(wù)器發(fā)送用戶名和密碼匙头。
2、服務(wù)器驗(yàn)證通過(guò)后仔雷,在當(dāng)前對(duì)話(session)里面保存相關(guān)數(shù)據(jù)乾胶,比如用戶角色、登錄時(shí)間等等朽寞。
3、服務(wù)器向用戶返回一個(gè) session_id斩郎,寫(xiě)入用戶的 Cookie脑融。
4、用戶隨后的每一次請(qǐng)求缩宜,都會(huì)通過(guò) Cookie肘迎,將 session_id 傳回服務(wù)器。
5锻煌、服務(wù)器收到 session_id妓布,找到前期保存的數(shù)據(jù),由此得知用戶的身份宋梧。

這種模式的問(wèn)題在于匣沼,擴(kuò)展性(scaling)不好。單機(jī)當(dāng)然沒(méi)有問(wèn)題捂龄,如果是服務(wù)器集群释涛,或者是跨域的服務(wù)導(dǎo)向架構(gòu),就要求 session 數(shù)據(jù)共享倦沧,每臺(tái)服務(wù)器都能夠讀取 session唇撬。

舉例來(lái)說(shuō),A 網(wǎng)站和 B 網(wǎng)站是同一家公司的關(guān)聯(lián)服務(wù)≌谷冢現(xiàn)在要求窖认,用戶只要在其中一個(gè)網(wǎng)站登錄,再訪問(wèn)另一個(gè)網(wǎng)站就會(huì)自動(dòng)登錄告希,請(qǐng)問(wèn)怎么實(shí)現(xiàn)扑浸?

一種解決方案是 session 數(shù)據(jù)持久化,寫(xiě)入數(shù)據(jù)庫(kù)或別的持久層暂雹。各種服務(wù)收到請(qǐng)求后首装,都向持久層請(qǐng)求數(shù)據(jù)。這種方案的優(yōu)點(diǎn)是架構(gòu)清晰杭跪,缺點(diǎn)是工程量比較大仙逻。另外驰吓,持久層萬(wàn)一掛了,就會(huì)單點(diǎn)失敗系奉。

另一種方案是服務(wù)器索性不保存 session 數(shù)據(jù)了檬贰,所有數(shù)據(jù)都保存在客戶端,每次請(qǐng)求都發(fā)回服務(wù)器缺亮。JWT 就是這種方案的一個(gè)代表翁涤。

2.2.2 JWT 的原理

JWT 的原理是,服務(wù)器認(rèn)證以后萌踱,生成一個(gè) JSON 對(duì)象葵礼,發(fā)回給用戶,就像下面這樣.

{
  "姓名": "張三",
  "角色": "管理員",
  "到期時(shí)間": "2018年7月1日0點(diǎn)0分"
}

以后并鸵,用戶與服務(wù)端通信的時(shí)候鸳粉,都要發(fā)回這個(gè) JSON 對(duì)象。服務(wù)器完全只靠這個(gè)對(duì)象認(rèn)定用戶身份园担。為了防止用戶篡改數(shù)據(jù)届谈,服務(wù)器在生成這個(gè)對(duì)象的時(shí)候,會(huì)加上簽名(詳見(jiàn)后文)弯汰。

服務(wù)器就不保存任何 session 數(shù)據(jù)了艰山,也就是說(shuō),服務(wù)器變成無(wú)狀態(tài)了咏闪,從而比較容易實(shí)現(xiàn)擴(kuò)展曙搬。

2.2.3 JWT 的數(shù)據(jù)結(jié)構(gòu)

實(shí)際的 JWT 大概就像下面這樣。

它是一個(gè)很長(zhǎng)的字符串鸽嫂,中間用點(diǎn)(.)分隔成三個(gè)部分织鲸。注意,JWT 內(nèi)部是沒(méi)有換行的溪胶,這里只是為了便于展示搂擦,將它寫(xiě)成了幾行。

JWT 的三個(gè)部分依次如下哗脖。

  • Header(頭部)
  • Payload(負(fù)載)
  • Signature(簽名)

寫(xiě)成一行瀑踢,就是下面的樣子。


Header.Payload.Signature

下面依次介紹這三個(gè)部分才避。

2.2.3.1 Header

Header 部分是一個(gè) JSON 對(duì)象橱夭,描述 JWT 的元數(shù)據(jù),通常是下面的樣子桑逝。


{
  "alg": "HS256",
  "typ": "JWT"
}

上面代碼中棘劣,alg屬性表示簽名的算法(algorithm),默認(rèn)是 HMAC SHA256(寫(xiě)成 HS256)楞遏;typ屬性表示這個(gè)令牌(token)的類型(type)茬暇,JWT 令牌統(tǒng)一寫(xiě)為JWT首昔。

最后,將上面的 JSON 對(duì)象使用 Base64URL 算法(詳見(jiàn)后文)轉(zhuǎn)成字符串糙俗。

2.2.3.2 Payload

Payload 部分也是一個(gè) JSON 對(duì)象勒奇,用來(lái)存放實(shí)際需要傳遞的數(shù)據(jù)。JWT 規(guī)定了7個(gè)官方字段巧骚,供選用赊颠。

  • iss (issuer):簽發(fā)人
  • exp (expiration time):過(guò)期時(shí)間
  • sub (subject):主題
  • aud (audience):受眾
  • nbf (Not Before):生效時(shí)間
  • iat (Issued At):簽發(fā)時(shí)間
  • jti (JWT ID):編號(hào)

除了官方字段,你還可以在這個(gè)部分定義私有字段劈彪,下面就是一個(gè)例子竣蹦。


{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

注意,JWT 默認(rèn)是不加密的沧奴,任何人都可以讀到草添,所以不要把秘密信息放在這個(gè)部分。

這個(gè) JSON 對(duì)象也要使用 Base64URL 算法轉(zhuǎn)成字符串扼仲。

2.2.3.3 Signature

Signature 部分是對(duì)前兩部分的簽名,防止數(shù)據(jù)篡改抄淑。

首先屠凶,需要指定一個(gè)密鑰(secret)。這個(gè)密鑰只有服務(wù)器才知道肆资,不能泄露給用戶矗愧。然后,使用 Header 里面指定的簽名算法(默認(rèn)是 HMAC SHA256)郑原,按照下面的公式產(chǎn)生簽名唉韭。


HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出簽名以后,把 Header犯犁、Payload属愤、Signature 三個(gè)部分拼成一個(gè)字符串,每個(gè)部分之間用"點(diǎn)"(.)分隔酸役,就可以返回給用戶住诸。

2.2.3.4 Base64URL

前面提到,Header 和 Payload 串型化的算法是 Base64URL涣澡。這個(gè)算法跟 Base64 算法基本類似贱呐,但有一些小的不同。

JWT 作為一個(gè)令牌(token)入桂,有些場(chǎng)合可能會(huì)放到 URL(比如 api.example.com/?token=xxx)奄薇。Base64 有三個(gè)字符+/=抗愁,在 URL 里面有特殊含義馁蒂,所以要被替換掉:=被省略呵晚、+替換成-/替換成_ 远搪。這就是 Base64URL 算法劣纲。

2.2.3.4

客戶端收到服務(wù)器返回的 JWT,可以儲(chǔ)存在 Cookie 里面谁鳍,也可以儲(chǔ)存在 localStorage癞季。

此后,客戶端每次與服務(wù)器通信倘潜,都要帶上這個(gè) JWT绷柒。你可以把它放在 Cookie 里面自動(dòng)發(fā)送,但是這樣不能跨域涮因,所以更好的做法是放在 HTTP 請(qǐng)求的頭信息Authorization字段里面废睦。


Authorization: Bearer <token>

另一種做法是,跨域的時(shí)候养泡,JWT 就放在 POST 請(qǐng)求的數(shù)據(jù)體里面嗜湃。

2.3 JWT 認(rèn)證流程

常規(guī)的 JWT 認(rèn)證流程如下如:



相比于 session 認(rèn)證,JWT 省去了服務(wù)器存儲(chǔ)用戶信息的過(guò)程澜掩。

JWT 常見(jiàn)校驗(yàn)流程:


其中設(shè)置 payload 校驗(yàn)規(guī)則一般是檢查 nbf购披、exp 以及用戶自定義的一些字段。

2.4 使用JWT實(shí)現(xiàn)單點(diǎn)登錄(完全跨域方案)

基于 cookie 的單點(diǎn)登錄模式有一個(gè)弊病在于肩榕,其對(duì)應(yīng)的多個(gè)站點(diǎn)的頂級(jí)域名必須相同刚陡。

主要有以下三步:
項(xiàng)目一開(kāi)始我先封裝了一個(gè)JWTHelper工具包(GitHub下載),主要提供了生成JWT株汉、解析JWT以及校驗(yàn)JWT的方法筐乳,其他還有一些加密相關(guān)操作。
接下來(lái)乔妈,我在客戶端項(xiàng)目中依賴JWTHelper工具包蝙云,并添加Interceptor攔截器,攔截需要校驗(yàn)登錄的接口路召。攔截器中校驗(yàn)JWT有效性贮懈,并在response中重新設(shè)置JWT的新值;
最后在JWT服務(wù)端优训,依賴JWT工具包朵你,在登錄方法中,需要在登錄校驗(yàn)成功后調(diào)用生成JWT方法揣非,生成一個(gè)JWT令牌并且設(shè)置到response的header中抡医。

參考 使用JWT實(shí)現(xiàn)單點(diǎn)登錄(完全跨域方案)https://blog.csdn.net/weixin_42873937/article/details/82460997

2.5 access_token和refresh_token

通常在使用JWT的時(shí)候會(huì)設(shè)置access_token和refresh_token兩個(gè)token,access_token有效期較短,refresh_token有效期較長(zhǎng)忌傻,當(dāng)access_token過(guò)期之后大脉,如果refresh_token沒(méi)有過(guò)期則可以換取新的access_token。我的疑問(wèn)在于為什么不直接給access_token設(shè)置一個(gè)較長(zhǎng)的有效期水孩。如果是為了安全镰矿,能拿到access_token,拿到refresh_token就是輕而易舉的事俘种;還有的說(shuō)法是refresh_token中可以存放比access_token更多秤标、驗(yàn)證起來(lái)更復(fù)雜的信息。

Token作為用戶獲取受保護(hù)資源的憑證宙刘,必須設(shè)置一個(gè)過(guò)期時(shí)間苍姜,否則一次登錄便可永久使用,認(rèn)證功能就失去了意義悬包。但是矛盾在于:過(guò)期時(shí)間設(shè)置得太長(zhǎng)衙猪,用戶數(shù)據(jù)的安全性將大打折扣;過(guò)期時(shí)間設(shè)置得太短布近,用戶就必須每隔一段時(shí)間重新登錄垫释,以獲取新的憑證,這會(huì)極大挫傷用戶的積極性撑瞧。針對(duì)這一問(wèn)題棵譬,我們可以利用Access / Refresh Token這一概念來(lái)平衡Token安全性和用戶體驗(yàn)。

Access / Refresh Token是什么季蚂?

上圖表示Access/Refresh Token在客戶端、認(rèn)證服務(wù)器琅束、資源服務(wù)器三者之間的傳遞關(guān)系扭屁,簡(jiǎn)單來(lái)說(shuō):

  • Access Token即“訪問(wèn)令牌”,是客戶端向資源服務(wù)器換取資源的憑證涩禀;
  • Refresh Token即“刷新令牌”料滥,是客戶端向認(rèn)證服務(wù)器換取Access Token的憑證。

Access / Refresh Token如何使用艾船?

上圖表示客戶端請(qǐng)求資源的過(guò)程中葵腹,Access Token 和 Refresh Token 是如何配合使用的:

1. 用戶提供身份信息(一般是[用戶名/密碼],利用客戶端向認(rèn)證服務(wù)器換取 Refresh Token和Access Token)屿岂;
2. 客戶端攜帶Access Token訪問(wèn)資源服務(wù)器践宴,資源服務(wù)器識(shí)別Access Token并返回資源;
3. 當(dāng)Access Token過(guò)期或失效爷怀,客戶端再一次訪問(wèn)資源服務(wù)器阻肩,資源服務(wù)器返回“無(wú)效token”報(bào)錯(cuò)
4. 客戶端通過(guò)Refresh Token向認(rèn)證服務(wù)器換取Access Token运授,認(rèn)證服務(wù)器返回新的Access Token烤惊。

3. 參考

(1)10分鐘了解JSON Web令牌(JWT)
https://baijiahao.baidu.com/s?id=1608021814182894637&wfr=spider&for=pc

(2)JWT的使用流程
https://blog.csdn.net/shmely/article/details/85915044

(3)JWT全面解讀乔煞、使用步驟
https://blog.csdn.net/achenyuan/article/details/80829401

(4)JSON Web Token 入門教程 -阮一峰
http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
【說(shuō)明】jwt結(jié)構(gòu)講得比較清晰。

(5)JWT(JSON Web Tokens)
https://www.cnblogs.com/zaixiuxing/p/6005968.html

(6)使用JWT實(shí)現(xiàn)單點(diǎn)登錄(完全跨域方案)
https://blog.csdn.net/weixin_42873937/article/details/82460997

(7)基于 JWT 的單點(diǎn)登錄設(shè)計(jì)
http://www.reibang.com/p/6c4e1804653f
【說(shuō)明】有邏輯圖柒室,介紹得清晰渡贾。

(8)JWT全面解讀、使用步驟
https://blog.csdn.net/achenyuan/article/details/80829401
【說(shuō)明】JAVA實(shí)現(xiàn)代碼

(9)看圖理解JWT如何用于單點(diǎn)登錄
https://www.shuzhiduo.com/A/kPzORnodxn/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雄右,一起剝皮案震驚了整個(gè)濱河市空骚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌不脯,老刑警劉巖府怯,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異防楷,居然都是意外死亡牺丙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門复局,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)冲簿,“玉大人,你說(shuō)我怎么就攤上這事亿昏÷吞蓿” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵角钩,是天一觀的道長(zhǎng)吝沫。 經(jīng)常有香客問(wèn)我,道長(zhǎng)递礼,這世上最難降的妖魔是什么惨险? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮脊髓,結(jié)果婚禮上辫愉,老公的妹妹穿的比我還像新娘。我一直安慰自己将硝,他們只是感情好恭朗,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著依疼,像睡著了一般痰腮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上律罢,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天诽嘉,我揣著相機(jī)與錄音,去河邊找鬼。 笑死虫腋,一個(gè)胖子當(dāng)著我的面吹牛骄酗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播悦冀,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼趋翻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了盒蟆?” 一聲冷哼從身側(cè)響起踏烙,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎历等,沒(méi)想到半個(gè)月后讨惩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寒屯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年荐捻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寡夹。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡处面,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菩掏,到底是詐尸還是另有隱情魂角,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布智绸,位于F島的核電站野揪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瞧栗。R本人自食惡果不足惜斯稳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沼溜。 院中可真熱鬧平挑,春花似錦游添、人聲如沸系草。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)找都。三九已至,卻和暖如春廊酣,著一層夾襖步出監(jiān)牢的瞬間能耻,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晓猛,地道東北人饿幅。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像戒职,于是被迫代替她去往敵國(guó)和親栗恩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

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