原文連接: https://learnku.com/laravel/t...
討論請前往專業的 Laravel 開發者論壇: https://learnku.com/Laravel
你能夠已經據說過 JSON Web Token (JWT) 是目前用於保護 API 的最新技術。laravel
與大多數安全主題同樣,若是你打算使用它,那頗有必要去了解它的工做原理(必定程度上)。問題在於,對 JWT 的大多數解釋都是技術性的,這一點讓人很頭疼。git
讓咱們看下,我可否解釋清楚 JWT 是如何在不引發你的注意下保護您的 API !github
某些 API 資源須要限制訪問 。例如,咱們不但願一個用戶可以更改另外一個用戶的密碼。web
這就是爲何咱們保護某些資源,使用戶在容許訪問以前提供他的 ID 和密碼——換句話說,咱們對它們進行身份驗證。算法
保護HTTP API的困難在於請求是 無狀態的 —— API 沒法知道是否有兩個請求來自同一用戶。數據庫
那麼,爲何不要求用戶在每次調用 API 時提供其 ID 和密碼呢?僅由於那將是可怕的用戶體驗。json
咱們須要的是一種容許用戶僅提供一次其憑證,隨後在後續請求中由服務器以另外一種方式標識的方式。安全
爲此設計了幾種系統,當前的最新標準是 JSON Web Token。服務器
這是一篇 關於該主題的精彩文章 ,它很好地比喻了 JSON Web Token 的工做方式:網絡
想象一下你要入住酒店,而不是一個 API 。「Token」是塑料酒店安全卡,可用於進入你的房間和使用酒店設施,但不能進入任何其餘人的房間。
當你退房的時候,你交回卡片。這相似於註銷。
一般, JSON Web Token 是經過 HTTP 請求頭髮送的。相似以下:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U
實際上, Token 部分是「Authorization: Bearer」以後的部分,僅是 HTTP 頭信息。
在你判定這是難以理解的胡言亂語前,有幾件事你很容易注意到。
首先,Token是由三個不一樣的字符串組成,以句點分隔。這三個部分是 Base64 編碼 後的內容,而且分別對應 Header , Payload 以及 Signature。
// Header eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 // Payload eyJzdWIiOiIxMjM0NTY3ODkwIn0 // Signature dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U
注意: Base64 是一種轉換字符串的方法,以確保在跨網絡傳輸期間不會被弄亂。這不是一種加密方式,任何人均可以 輕鬆解碼 以查看原始數據。
咱們能夠對這些字符串進行解碼,以更好地瞭解JWT的結構。
如下是 Token 中的已解碼 Header 部分。Header 是 Token 的元信息。它並無告訴咱們不少幫助你創建基本理解的知識,所以咱們不會對此進行任何詳細介紹。
{ "alg": "HS256", "typ": "JWT" }
Payload 能引發更多的關注。若是你想, Payload 能夠包含任何數據,可是若是 Token 的目的是 API 訪問身份驗證,則能夠僅包含用戶 ID 。
{ "userId": "1234567890" }
請注意, Payload 不安全 。 任何人均可以解碼 Token ,並確切瞭解 Payload 中的內容。所以,咱們一般會包含一個 ID ,而不是諸如用戶電子郵件之類的敏感識別信息。
即便 Payload 是在 API 上識別用戶所須要的所有,它也不能提供身份驗證的方法。若是其中包含全部內容,則有人能夠輕鬆找到你的用戶 ID 並僞造 Token 。
所以,這使咱們進入了 Signature 部分,這是認證 Token 的關鍵部分。
在解釋簽名如何工做以前,咱們須要定義什麼是哈希算法。
首先,它是一個將字符串轉換爲稱爲 Hash 的新字符串的函數。例如,假設咱們要對字符串「Hello, world」進行哈希處理。這是咱們使用 SHA256 哈希算法獲得的輸出:
4ae7c3b6ac0beff671efa8cf57386151c06e58ca53a78d83f36107316cec125f
哈希的最重要屬性是 你沒法經過哈希算法來查看 Hash 的原始文本 。
有許多不一樣類型的哈希算法,但 SHA256 一般與 JWT 一塊兒使用。
換句話說,咱們不能根據上面的散列值算出原始字符串是 Hello,world。哈希很是複雜,以致於沒法猜想原始字符串。
回到 JWT 結構,來看一下令牌的第三部分,簽名。實際上須要計算:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), "secret string" );
下面是對這裏發生的狀況作解釋:
首先, HMACSHA256
是哈希函數的名稱, 並帶有兩個參數:要散列的字符串,以及「secret」。
其次,咱們哈希的字符串是 base 64 的編碼報頭,加上 base 64 的編碼有效載荷。
第三, secret 是任意一段字符串,只有服務器知道。
問. 爲何在簽名散列中包含標頭和有效負載?
這確保了簽名對於此特定令牌是惟一的。*
問. secret 是什麼?
爲了回答這個問題,讓咱們考慮一下如何僞造令牌。
咱們以前說過,您沒法經過查看輸出來肯定哈希的輸入。可是,因爲咱們知道簽名包括標頭和有效負載,由於它們是公共信息,因此若是您知道哈希算法(提示:一般在標頭中指定),則能夠生成相同的哈希。
可是隻有服務器知道的祕密 不是 公共信息。將其包含在哈希中可防止某人生成本身的哈希來僞造令牌。並且因爲散列會掩蓋用於建立散列的信息,所以任何人都沒法從散列中找出祕密。
將私有數據添加到哈希中的過程稱爲 salting ,幾乎不可能破解令牌。
所以,如今您對令牌的建立方式有了一個很好的瞭解。您如何使用它來驗證您的API?
用戶登陸時會生成令牌,令牌會與用戶模型一塊兒存儲在數據庫中。
if (passwordCorrect) { user.token = generateToken(user.id); user.save(); }
而後令牌做爲authorization
頭附加到登陸請求的響應中。
loginController.js
if (passwordCorrect) { user.token = generateToken(user.id); user.save(); res.headers("authorization", `Bearer ${token}`).send(); }
如今,客戶端有了令牌,他們能夠將其附加到任何未來的請求以身份驗證用戶。
當服務器收到帶有受權令牌的請求時,將發生如下狀況:
1.它解碼令牌並從有效載荷中提取ID。
2.它使用此ID在數據庫中查找用戶。
3.它將請求令牌與用戶模型中存儲的令牌進行比較。若是它們匹配,則對用戶進行身份驗證。
authMiddleware.js
const token = req.header.token; const payload = decodeToken(token); const user = User.findById(payload.id); if (user.token = token) { // 經過身份認證 } else { // 未經過身份認證 }
若是用戶註銷,只需刪除附加到用戶模型的令牌,如今令牌將再也不起做用。用戶將須要再次登陸以生成新令牌。
logoutController.js
user.token = null; user.save();
所以,這是關於如何使用 JSON Web 令牌保護 API 的最基本的說明。但願你不會很頭疼。
不過,相關的話題還有不少,因此這裏有一些額外的讀物:
原文連接: https://learnku.com/laravel/t...
討論請前往專業的 Laravel 開發者論壇: https://learnku.com/Laravel