JWT-JSON Web令牌的深入介紹
從桌面應用程序到Web應用程序或移動應用程序,身份驗證是幾乎所有應用程序中最重要的部分之一。 本教程是JWT(JSON Web令牌)的深入介紹,可幫助您瞭解:
- 基於會話的身份驗證與基於令牌的身份驗證(爲什麼JWT誕生了)
- JWT是如何工作的。
- 如何創建JWT。
- 我們如何保護我們的應用程序並驗證JWT。
- 更多實踐:
– 使用Spring Security和JWT身份驗證的安全Spring Boot應用程序
– Node.js –使用JSONWebToken示例(JWT)的基於令牌的身份驗證
– Spring Boot,MongoDB:基於Spring Security的JWT身份驗證
– 使用Vuex和Vue路由器進行Vue.js JWT身份驗證
– 使用HttpInterceptor和路由器進行Angular 8 JWT身份驗證
– React JWT身份驗證(無Redux)示例
使用JWT的Spring Security概述:
[按體系結構使用了 MySQL,Spring Security示例的Spring Boot JWT Auth[(https://bezkoder.com/spring-boot-jwt-mysql-spring-security-architecture/)
內容
- 基於會話的身份驗證和基於令牌的身份驗證
- JWT是如何工作的
- 如何創建JWT
- 標頭
- 有效載荷
- 簽名
- 結合一切
- JWT如何保護我們的數據
- 服務端如何校驗從客戶端過來的JWT
- 結論
- 進一步閱讀
基於會話的身份驗證和基於令牌的身份驗證
對於使用任何網站,移動應用程序或桌面應用程序……您幾乎需要創建一個帳戶,然後使用該帳戶登錄以訪問該應用程序的功能。 我們稱該行爲爲身份驗證。
那麼,如何驗證帳戶?
首先,我們來看看過去流行的網站使用的一種簡單方法:基於會話的身份驗證。
在上圖中,當用戶登錄網站時,服務器將爲該用戶生成一個會話並將其存儲(在內存或數據庫中)。服務器還會爲客戶端返回一個SessionId,以將其保存在瀏覽器Cookie中。
服務器上的會話具有到期時間。在此時間之後,該會話已過期,用戶必須重新登錄才能創建另一個會話。
如果用戶已登錄並且會話尚未到期,則Cookie(包括SessionId)將始終與所有向服務器的HTTP請求一起使用。服務器將比較此SessionId與存儲的會話以進行身份驗證並返回相應的響應。
沒關係。但是爲什麼我們需要基於令牌的身份驗證?
答案是我們不僅有網站,而且那裏有很多平臺。
假設我們有一個與Session配合良好的網站。有一天,我們想爲移動(本地應用程序)實現系統,並與當前的Web應用程序使用同一數據庫。我們應該做什麼?我們無法使用基於會話的身份驗證對使用Native App的用戶進行身份驗證,因爲這些類型沒有Cookie。
我們是否應該構建另一個支持Native Apps的後端項目?
還是應該爲Native App用戶編寫一個身份驗證模塊?
這就是基於令牌的身份驗證誕生的原因。
使用此方法,服務器會將用戶登錄狀態編碼爲JSON Web令牌(JWT),並將其發送給客戶端。 如今,許多RESTful API都在使用它。 讓我們轉到下一部分,我們將知道它是如何工作的。
JWT是如何工作的
現在看下面的流程:
您會發現它很容易理解。 服務器沒有創建會話,而是從用戶登錄數據生成了JWT,並將其發送給客戶端。 客戶端保存JWT,從現在開始,來自客戶端的每個請求都應附加到該JWT(通常在標頭處)。 服務器將驗證JWT並返回響應。
要在客戶端存儲JWT,取決於您使用的平臺:
- 瀏覽器:Local Storage
- IOS: Keychain
- Android: SharedPreferences
這是基於令牌的身份驗證流程的概述。 在下一節中,您將更深入地瞭解它。
如何創建JWT
首先,您應該瞭解JWT的三個重要部分:
- 標頭
- 有效載荷
- 簽名
標頭
標頭回答了這個問題:我們將如何計算JWT?
現在來看一個標頭示例,它是一個JSON對象,如下所示:
{
"typ": "JWT",
"alg": "HS256"
}
– typ是“ type”,表示此處的令牌類型是JWT。
– alg代表“算法”,它是一種用於生成令牌簽名的哈希算法。 在上面的代碼中,HS256是HMAC-SHA256 –使用密鑰的算法。
有效載荷
有效負載可幫助我們回答:我們想在JWT中存儲什麼?
這是有效負載示例:
{
"userId": "abcd12345ghijk",
"username": "bezkoder",
"email": "[email protected]",
// standard fields
"iss": "zKoder, author of bezkoder.com",
"iat": 1570238918,
"exp": 1570238992
}
在上面的JSON對象中,我們存儲3個用戶字段:userId,username, email。 您可以保存所需的任何字段。
我們也有一些Standard Fields。 它們是可選的。
- iss(Issuer):誰發行JWT
- iat(發佈於):JWT的發佈時間:
- exp(到期時間):JWT到期時間
我們可以在[https://en.wikipedia.org/wiki/JSON_Web_Token#Standard_fields](https://en.wikipedia.org/wiki/JSON_Web_Token#Standard_fields]查看更多的Standard Fields
簽名
這部分是我們使用上面我告訴過您的哈希算法的地方。
查看下面獲得簽名的代碼:
const data = Base64UrlEncode(header) + '.' + Base64UrlEncode(payload);
const hashedData = Hash(data, secret);
const signature = Base64UrlEncode(hashedData);
讓我們解釋一下。
–首先,我們對Header和Payload進行編碼,並用點將它們連接起來。
data = '[encodedHeader].[encodedPayload]'
–接下來,我們使用帶有祕鑰字符串的Hash算法(在Header中定義)對數據進行哈希處理。
–最後,我們對哈希結果進行編碼以獲得簽名。
結合一切
在擁有Header,Payload,Signature之後,我們將它們組合成JWT標準結構:header.payload.signature。
以下代碼將說明我們如何做到這一點。
const encodedHeader = base64urlEncode(header);
/* Result */
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"
const encodedPayload = base64urlEncode(payload);
/* Result */
"eyJ1c2VySWQiOiJhYmNkMTIzNDVnaGlqayIsInVzZXJuYW1lIjoiYmV6a29kZXIiLCJlbWFpbCI6ImNvbnRhY3RAYmV6a29kZXIuY29tIn0"
const data = encodedHeader + "." + encodedPayload;
const hashedData = Hash(data, secret);
const signature = base64urlEncode(hashedData);
/* Result */
"crrCKWNGay10ZYbzNG3e0hfLKbL7ktolT7GqjUMwi3k"
// header.payload.signature
const JWT = encodedHeader + "." + encodedPayload + "." + signature;
/* Result */
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJhYmNkMTIzNDVnaGlqayIsInVzZXJuYW1lIjoiYmV6a29kZXIiLCJlbWFpbCI6ImNvbnRhY3RAYmV6a29kZXIuY29tIn0.5IN4qmZTS3LEaXCisfJQhrSyhSPXEgM1ux-qXsGKacQ"
JWT如何保護我們的數據
JWT不保護您的數據
JWT完全不會隱藏,掩蓋和保護數據。 您可以看到,生成JWT(標頭,有效負載,簽名)的過程僅對數據進行哈希處理,而不對數據進行加密。
JWT的目的是證明數據是由真實來源生成的。
那麼,如果有中間人攻擊可以獲取JWT,然後解碼用戶信息怎麼辦? 是的,這是可能的,因此請始終確保您的應用程序具有HTTPS加密。
服務器如何從客戶端驗證JWT
在上一節中,我們使用Secret字符串創建簽名。 此Secret字符串對於每個應用都是唯一的,並且必須安全地存儲在服務器端。
從客戶端接收JWT時,服務器獲取簽名,並驗證簽名是否已通過與上述相同的算法和Secret字符串正確地進行了哈希處理。 如果它與服務器的簽名匹配,則JWT有效。
重要!
當發送給服務端時,有經驗的程序猿仍然可以添加或編輯有效載荷信息。 在這種情況下我們該怎麼辦?
我們先存儲令牌,然後再將其發送給客戶端。 它可以確保客戶端稍後發送的JWT有效。
此外,將用戶的令牌保存在服務器上還將使系統的強制註銷功能受益。
結論
永遠不會有最佳的身份驗證方法。 這取決於用例和實現方式。
但是,對於要在許多平臺上擴展爲大量用戶的應用程序,首選JWT身份驗證,因爲令牌將存儲在客戶端。
祝您學習愉快,再見!