ASP.NET Core 基於JWT的認證(一)

WarrenRyan發表於2019-02-24

ASP.NET Core 基於JWT的認證(一)

Json web token (JWT), 是為了在網路應用環境間傳遞宣告而執行的一種基於JSON的開放標準((RFC 7519).該token被設計為緊湊且安全的,特別適用於分散式站點的單點登入(SSO)場景。JWT的宣告一般被用來在身份提供者和服務提供者間傳遞被認證的使用者身份資訊,以便於從資源伺服器獲取資源,也可以增加一些額外的其它業務邏輯所必須的宣告資訊,該token也可直接被用於認證,也可被加密。

我們知道,http協議本身是一種無狀態的協議,而這就意味著如果使用者向我們的應用提供了使用者名稱和密碼來進行使用者認證,那麼下一次請求時,使用者還要再一次進行使用者認證才行,因為根據http協議,我們並不能知道是哪個使用者發出的請求,所以為了讓我們的應用能識別是哪個使用者發出的請求,我們只能在伺服器儲存一份使用者登入的資訊,這份登入資訊會在響應時傳遞給瀏覽器,告訴其儲存為cookie,以便下次請求時傳送給我們的應用,這樣我們的應用就能識別請求來自哪個使用者了。

幾種常見的傳統認證機制

HTTP Basic Auth

HTTP Basic Auth簡單點說明就是每次請求API時都提供使用者的usernamepassword,簡言之,Basic Auth是配合RESTful API 使用的最簡單的認證方式,只需提供使用者名稱密碼即可,但由於有把使用者名稱密碼暴露給第三方客戶端的風險,在生產環境下被使用的越來越少。因此,在開發對外開放的RESTful API時,儘量避免採用HTTP Basic Auth

OAuth

OAuth(開放授權)是一個開放的授權標準,允許使用者讓第三方應用訪問該使用者在某一web服務上儲存的私密的資源(如照片,影片,聯絡人列表),而無需將使用者名稱和密碼提供給第三方應用。

OAuth允許使用者提供一個令牌,而不是使用者名稱和密碼來訪問他們存放在特定服務提供者的資料。每一個令牌授權一個特定的第三方系統(例如,影片編輯網站)在特定的時段(例如,接下來的2小時內)內訪問特定的資源(例如僅僅是某一相簿中的影片)。這樣,OAuth讓使用者可以授權第三方網站訪問他們儲存在另外服務提供者的某些特定資訊,而非所有內容
下面是OAuth2.0的流程:

Cookie認證機制就是為一次請求認證在服務端建立一個Session物件,同時在客戶端的瀏覽器端建立了一個Cookie物件;透過客戶端帶上來Cookie物件來與伺服器端的session物件匹配來實現狀態管理的。預設的,當我們關閉瀏覽器的時候,cookie會被刪除。但可以透過修改Cookieexpire time使cookie在一定時間內有效;
兩種對比

Token 簡介

JWT (Json Web Token)是為了在網路應用環境間傳遞宣告而執行的一種基於JSON的開放標準。

JWT的宣告一般被用來在身份提供者和服務提供者間傳遞被認證的使用者身份資訊,以便於從資源伺服器獲取資源。比如用在使用者登入上。

有些朋友可能會認為,我登入只需要用快取或者資料庫記錄下一個特徵碼或者是Cookies就可以了,為什麼要使用JWT呢?我們知道一個資料庫或者是一個軟體,損耗時間最大的地方就是我們的 I/O(輸入輸出,通常指的就是硬碟的讀寫),因此我們選擇解碼一次HS256,對於現在的計算能力強大的計算機而言,解一次HS256比訪問一次磁碟要快得多。

基於token的鑑權機制類似於http協議也是無狀態的,它不需要在服務端去保留使用者的認證資訊或者會話資訊。這就意味著基於token認證機制的應用不需要去考慮使用者在哪一臺伺服器登入了,這就為應用的擴充套件提供了便利。
流程上是這樣的:

  • 使用者使用使用者名稱密碼來請求伺服器
  • 伺服器進行驗證使用者的資訊
  • 伺服器透過驗證傳送給使用者一個token
  • 客戶端儲存token,並在每次請求時附送上這個token值
  • 服務端驗證token值,並返回資料

這個token必須要在每次請求時傳遞給服務端,它應該儲存在請求頭裡, 另外,服務端要支援CORS(跨來源資源共享)策略,一般我們在服務端這麼做就可以了Access-Control-Allow-Origin: *。
那麼我們現在回到JWT的主題上。

JWT 的組成

我們先來看一段jwt

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

仔細觀察我們可以發現這一段字串中含有兩個 " . ",這兩個 " . "jwt分成了三份,我們分別成為頭部、荷載資訊、簽證資訊。那麼這三部分的分工是什麼呢?

JWT的頭部承載了兩個資訊

  • 宣告型別,對於Jwt來說就是jwt
  • 加密演算法,通常使用SHA256,HS256

完整的頭部應該是像這樣的一個Json

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

將頭部Json進行base64加密就得到了我們的第一部分

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

Payload

第二部分是荷載資訊,Payload,你可以理解為我們的JWT是一輛大倉庫,第一部分頭部就是倉庫的名稱編號等基礎資訊,而荷載資訊就是倉庫的本身,包含了倉庫裡面的所有貨物。這些資訊又包含了三個部分:

  • 標準中註冊的宣告
  • 公共的宣告
  • 私有的宣告

標準中註冊的宣告 (建議但不強制使用)

  • iss: jwt簽發者

  • sub: jwt所面向的使用者

  • aud: 接收jwt的一方

  • exp: jwt的過期時間,這個過期時間必須要大於簽發時間

  • nbf: 定義在什麼時間之前,該jwt都是不可用的.

  • iat: jwt的簽發時間

  • jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。

公共的宣告 :

公共的宣告可以新增任何的資訊,一般新增使用者的相關資訊或其他業務需要的必要息。但不建議新增敏感資訊,因為該部分在客戶端可解密。

私有的宣告 :

私有宣告是提供者和消費者所共同定義的宣告,一般不建議存放敏感資訊,因為base64是對稱解密的,意味著該部分資訊可以歸類為明文資訊。

事實上我們的Header和Payload都是基於base64加密的,這種密文都是可以對稱解密的,因此請不要存放敏感資訊。

定義一個payload:

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

進行base64加密後,得到了我們的第二部分

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

Signature

Jwt的第三部分是一個簽證資訊,這個簽證資訊由三部分組成:

  • header (base64後的)
  • payload (base64後的)
  • secret

這一部分可以理解為對前部分的一個校驗,將前兩部分加密後的密文透過在Header中定義的加密方式,與服務端所傳入的金鑰進行一次加密,假如前兩部分的資訊被篡改的話,必然通不過最後一部分簽證的校驗。因此透過這樣保證了Jwt的安全性。

因此,儲存並隱藏好我們的加密金鑰是非常重要的,假設洩露了,就意味著任何知道金鑰的人都可以輕鬆的對jwt進行自我簽發和驗證。






作  者:WarrenRyan
出  處:https://www.cnblogs.com/WarrenRyan/
關於作者:熱愛數學、熱愛機器學習,喜歡彈鋼琴的不知名小菜雞。
版權宣告:本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。若需商用,則必須聯絡作者獲得授權。
特此宣告:所有評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信
聲援博主:如果您覺得文章對您有幫助,可以點選文章右下角推薦一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!


博主一些其他平臺:
微信公眾號:寤言不寐
BiBili——小陳的學習記錄
Github——StevenEco
BiBili——記錄學習的小陳(計算機考研紀實)
掘金——小陳的學習記錄
知乎——小陳的學習記錄

聯絡方式:

電子郵件:cxtionch@live.com

社交媒體聯絡二維碼:

ASP.NET Core 基於JWT的認證(一)

相關文章