小馬經常看到招聘要求中會寫著一個詞:JWT。沒接觸過的同學可能一愣,這是啥高級玩意?看起來很唬人的樣子,不能查,一查就是個token生成方式。好,那就來了解一下吧。
什麼是JWT
JSON Web Token (JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,該token被設計為緊湊且安全的,特別適用於分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便於從資源伺服器獲取資源,也可以增加一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用於認證,也可被加密。
啥意思呢?就是說我是一種token生成方式/標準,可以用於身份認證也可以用於傳遞數據,並且我是可加密的。也就是要生產token的話,小馬要是自己想規定一個token生成方式就不按JWT標準,也是沒問題的。
為什麼會有JWT這玩意呢
我們應該先來談一談傳統的session認證和基於token的認證。
1、傳統的session認證
因為HTTP協議本身是無狀態的,而在本次會話過程中我們的每一次請求都需要進行用戶身份認證的保持,於是將第一次請求服務端校驗後的用戶身份標誌(session_id)保存在客戶端(cookie)便於下次請求時帶上身份,這樣服務端就能識別身份了。借用一個圖片來理解。
這種方式的弊端在於,因為是基於cookie來進行用戶識別的, cookie如果被截獲,用戶就會很容易受到跨站請求偽造(CSRF)的攻擊。由於依賴於cookie和session不利於作單點登錄(session共享和跨域CORS)和沒有cookie機制的(APP)的實現。
埋一個彩蛋:如果禁用了cookie,session機制還可以用嗎?可以,把session_id放請求參數裡。session的存儲方式有哪些?默認存文件,還可以存DB和cache。如果就是要基於session實現單點登錄呢,即一處登錄其他系統都能用?同域下,將session存儲共享即可。
2、基於token的鑑權
基於token機制不需要知道用戶在哪臺機器登陸,服務端只認token標誌。可以支持CORS跨域,不過服務端要同時支持,一般設置Access-Control-Allow-Origin: *。借JWT的一張圖來助於理解。JWT其實就是token機制的一種實現,下面再講。
3、JWT原理
我們上面盤了一下得到,JWT其實就是個token生成方式。那它是怎麼個生法呢?
JWT是由三段信息構成的,分別是Header,Payload,Signature,將這三段信息文本用點連結一起就構成了JWT字符串。看起來是這個樣子:aaa.bbb.ccc。
Header典型的由兩部分組成:token的類型(「JWT」)和算法名稱(比如:HMAC SHA256或者RSA等等)。例如{'alg':"HS256",'typ':"JWT"},用Base64對這個JSON加密(是對稱加密)就得到JWT的第一部分。
Payload載荷就是存放有效信息的地方(可以理解為皮卡的後備箱)。有效信息包含三個部分:標準中註冊的聲明(這裡有一組預定義的聲明,它們不是強制的,但是推薦。比如:iss (issuer), exp (expiration time), sub (subject), aud (audience)等),公共的聲明(可以隨意定義任何信息),私有的聲明(是提供者和消費者所共同定義的聲明,用於在同意使用它們的各方之間共享信息)。這三部分信息都不建議放敏感信息,因為是base64對稱加密的,除非信息本身已經有做過一層加密處理。第二段信息格式例子如下:{"sub":'123456789',"name":'xiaoma',"level":'1'},同樣進行Base64編碼就得到JWT的第二部分。
Signature籤名(可以理解為駕照),對編碼過的Header、編碼過的Payload、一個密鑰(私鑰),籤名算法用是Header中指定的那個,然對它們籤名得到的就是JWT的三部分。類似Signature=HS256(base64(Header)+base64(Payload),secret)。私鑰可以防止篡改和驗證有效性。
實踐演練
好了,我們得到了一個JWT方式的token。那這個token放哪裡呢? query參數嗎?最好把JWT放在HTTP請求的Header Authorization,格式是Authorization: Bearer jwtStr。類似如下:
後記
筆者認為,JWT也就是個token生成方式和普通token本質沒啥區別。要是JWT串被截取和普通token一樣同樣逃不掉權限被劫持,最好用HTTPS加密請求。為了安全,服務端對於敏感權限需要重新驗證,令牌要設置合理的過期時間。
JWT不僅僅可以實現身份認證還可以在跨域post請求時將請求參數加入到有效載荷中,實現post跨域請求。
本文主要助於理解,水平有限,不到之處歡迎指正。