菜菜,上次你講的cookie和session認證方式,我此次面試果真遇到了web
結果怎麼樣?面試
結果面試官問我還有沒有更好的方式?算法
看來你又掛了apache
別說了,傷心呀。到底還有沒有更好的方式呢?json
你猜?後端
經過上一篇你大致已經瞭解session和cookie認證了,session認證須要服務端作大量的工做來保證session信息的一致性以及session的存儲,因此現代的web應用在認證的解決方案上更傾向於客戶端方向,cookie認證是基於客戶端方式的,可是cookie缺點也很明顯,到底有哪些缺點能夠跳轉上一次的文章。那有沒有一種比較折中的方案呢?有的跨域
把認證信息保存在客戶端,關鍵點就是安全的驗證,若是能解決認證信息的安全性問題,徹底能夠把認證信息保存在客戶端,服務端徹底無認證狀態,這樣的話服務端擴展起來要方便不少。關於信息的安全解決方案,如今廣泛的作法就是簽名機制,像微信公衆接口的驗證方式就基於簽名機制。安全
簽名,就是隻有信息的發送者才能產生的別人沒法僞造的一段數字串,這段數字串同時也是對信息的發送者發送信息真實性的一個有效證實。服務器
當用戶成功登錄系統併成功驗證有效以後,服務器會利用某種機制產生一個token字符串,這個token中能夠包含不少信息,例如來源IP,過時時間,用戶信息等, 把這個字符串下發給客戶端,客戶端在以後的每次請求中都攜帶着這個token,攜帶方式其實很自由,不管是cookie方式仍是其餘方式均可以,可是必須和服務端協商一致才能夠。固然這裏我不推薦cookie。當服務端收到請求,取出token進行驗證(能夠驗證來源ip,過時時間等信息),若是合法則容許進行操做。微信
基於token的驗證方式也是現代互聯網普通使用的認證方式,那它有什麼優勢嗎?
1. 支持跨域訪問,Cookie是不容許垮域訪問的,這一點對Token機制是不存在的,前提是傳輸的用戶認證信息經過HTTP頭傳輸.
2. 無狀態:Token機制在服務端不須要存儲session信息,由於Token自身包含了全部登陸用戶的信息,只須要在客戶端的cookie或本地介質存儲狀態信息.
3. 解耦 不須要綁定到一個特定的身份驗證方案。Token能夠在任何地方生成,只要在你的API被調用的時候,你能夠進行Token生成調用便可.
4. 適用性更廣:只要是支持http協議的客戶端,就可使用token認證。
5. 服務端只須要驗證token的安全,沒必要再去獲取登陸用戶信息,由於用戶的登陸信息已經在token信息中。
6. 基於標準化:你的API能夠採用標準化的 JSON Web Token (JWT). 這個標準已經存在多個後端庫(.NET, Ruby, Java,Python,PHP)和多家公司的支持(如:Firebase,Google, Microsoft).
那基於token的認證方式有哪些缺點呢?
1. 網絡傳輸的數據量增大:因爲token中存儲了大量的用戶和安全相關的信息,因此比單純的cookie信息要大不少,傳輸過程當中須要消耗更多流量,佔用更多帶寬,
2. 和全部的客戶端認證方式同樣,若是想要在服務端控制token的註銷有難度,並且也很難解決客戶端的劫持問題。
3. 因爲token信息在服務端增長了一次驗證數據完整性的操做,因此比session的認證方式增長了cpu的開銷。
可是總體來看,基於token的認證方式仍是比session和cookie方式要有很大優點。在所知的token認證中,jwt是一種優秀的解決方案
JSON Web Token (JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,用於做爲JSON對象在各方之間安全地傳輸信息。該信息能夠被驗證和信任,由於它是數字簽名的。
一個JWT實際上就是一個字符串,它由三部分組成,頭部、載荷與簽名。
頭部
header典型的由兩部分組成:token的類型(「JWT」)和算法名稱(好比:HMAC SHA256或者RSA等等)。
{
"alg": "HS256",
"typ": "JWT"
}
Payload
Payload 部分也是一個JSON對象,用來存放實際須要傳遞的數據。JWT 規定了7個官方字段,供選用。
iss (issuer):簽發人
exp (expiration time):過時時間
sub (subject):主題
aud (audience):受衆
nbf (Not Before):生效時間
iat (Issued At):簽發時間
jti (JWT ID):編號
除了以上字段以外,你徹底能夠添加本身想要的任何字段,這裏仍是提醒一下,因爲jwt的標準,信息是不加密的,因此一些敏感信息最好不要添加到json裏面
{
"Name":"菜菜",
"Age":18
}
Signature
爲了獲得簽名部分,你必須有編碼過的header、編碼過的payload、一個祕鑰(這個祕鑰只有服務端知道),簽名算法是header中指定的那個,然對它們簽名便可。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
算出簽名之後,把 Header、Payload、Signature 三個部分拼成一個字符串,每一個部分之間用"點"(.)分隔,就能夠返回給用戶。須要提醒一下:base64是一種編碼方式,並不是加密方式。
基於token的認證方式,大致流程爲:
1. 客戶端攜帶用戶的登陸憑證(通常爲用戶名密碼)提交請求
2. 服務端收到登陸請求,驗證憑證正確性,若是正確則按照協議規定生成token信息,通過簽名並返回給客戶端
3. 客戶端收到token信息,能夠保存在cookie或者其餘地方,之後每次請求的時候都攜帶上token信息
4. 業務服務器收到請求,驗證token的正確性,若是正確則進行下一步操做
這裏再重複一次,不管是token認證,cookie認證,仍是session認證,一旦別人拿到客戶端的標識,仍是能夠僞造操做。因此採用任何一種認證方式的時候請考慮加入來源ip或者白名單,過時時間,另外有條件的狀況下必定要使用https。