JWT的組成
JWT是由三組JSON物件Header、Payload與Signature所組成,這三組JSON物件會各自編碼,物件之間以.
做區隔組成一串Token字串。
組合成如Header.Payload.Signature
的字串。
實際組成的JWT會如下顯示:
Header
由"alg"與"typ"兩個欄位組成。
alg( algorithm): token加密的演算法,如HMAC、SHA256、RSA。
typ( type): token的類型,基本上就是 JWT。
Payload
這裡放的是聲明 (Claim) 內容,也就是用來放傳遞訊息的地方。
JWT 標準公定的Registered claims有七種。
- iss (issuer):簽發人
- exp (expiration time):過期時間
- sub (subject):主題
- aud (audience):接收人
- nbf (Not Before):開始生效時間
- iat (Issued At):簽發時間
- jti (JWT ID):編號, JWT 的 Id
因為 Payload 傳遞的訊息最後也是透過 Base64 進行編碼,所以是可以被破解的,所以放在Payload的訊息必須為公開、比較不機密的資訊。
Signature
由三部分組成:
- 以Base64 編碼的Header
- 以Base64 編碼的Payload
- secret(密鑰)
Header跟 Payload中間用.
來串接,secret 是存放在伺服器端的秘密字串,最後將這三個部分串接在一起的字串,以Header定義的演算法進行加密。
下圖為整個Token產生的流程圖:
JWT實作
以ASP.NET Core 5.0的RESTful API來實作JWT,包含登入驗證、產生Token、驗證Token與Token刷新。
專案採用這裡延續撰寫。
以專案中的API套用JWT驗證機制,來驗證訪問token是否有權限。
會使用到的資料表有三個:
Users資料表:用來儲存使用者帳號密碼。
UserToken資料表:用來儲存Token與RefreshToken。
OrderList資料表:驗證後查詢的資料。
實作步驟
- 設定JWT Token驗證
- 建立產生JWT Token的方法
- 建立RefreshToken的機制
- 呼叫API產生Token與驗證
- HttpClient呼叫API
設定JWT Token驗證
設定JWT Token的密鑰與註冊驗證的服務。
NuGet下載套件
Microsoft.AspNetCore.Authentication.JwtBearer
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.AspNetCore.Identity.UI
appsettings.json
在appsettings.json中加入JWT的section "JwtConfig"與JWT的密鑰 "Secret"。
"JwtConfig": {
"Secret": "rdqziegmbzhflvkjpvhuadenwoxgpabu"
}
(https://www.browserling.com/tools/random-string)
建立密鑰
在專案中新增Configuration資料夾,並新增JwtConfig Class。
用來接收傳遞Secret密鑰。
Startup設定
在Startup.cs的ConfigureServices方法中,加入以下程式碼。
之後在程式中注入JwtConfig,即可取得"appsettings.json"中的"JwtConfig"的值。
接著,繼續在Startup.cs的ConfigureServices方法中,新增驗證配置。
建立TokenValidationParameters,用來驗證客戶端傳過來的token是否合法。並透過AddAuthentication註冊驗證的服務,並設定JWT的驗證配置。
ConfigureServices方法的詳細程式碼如下:
然後,在Startup.cs的Configure方法中,app.UseAuthorization()授權之前加入app.UseAuthentication()識別身分。
這樣才能在授權之前,先驗證是否為有效的身分。
ASP.NET Core 中的授權
ASP.NET Core 中的授權是由 AuthorizeAttribute 和其各種參數所控制。 在其最基本的表單中,將 [Authorize]
屬性套用至控制器、動作或 Razor 頁面,會限制對該元件已驗證使用者的存取。
Authorize]篩選器,限制呼叫時須透過驗證機制。
也可以使用 AllowAnonymous
屬性來允許未經驗證的使用者存取個別動作。
AllowAnonymous]篩選器,不用驗證也能呼叫
建立產生JWT Token的方法
新增Mehod來檢核登入帳號,並產生JWT Token。
建立驗證的回傳訊息
在Configuration資料夾中,建立新class命名AuthResult,用來回覆驗證後的訊息。
建立DTO
建立DTO(data transfer objects),在Models資料夾裡新增DTOs資料夾。
並在DTOs資料夾中新增兩個資料夾Requests跟Responses。
在Models/DTOs/Requests中,新增UserLoginRequest.cs,做為登入的Request。
在Models/DTOs/Response中,新增UserLoginResponse.cs,並直接繼承AuthResult.cs。
AuthManagementController
在Controllers資料夾中,新增AuthManagementController.cs,並注入JwtConfig與MyDBContext。
新增Method來產生JWT Token
新增GenerateJwtToken方法,用來產生JWT Token。
程式碼如下:
新增Method做為登入用
新增Login方法,做為登入的API接口。在驗證帳號、密碼後,呼叫GenerateJwtToken方法產生JWT Token並回傳資訊。
程式碼如下:
建立RefreshToken的機制
新增Mehod,驗證Token與RefreshToken後,建立新的Token並回傳。
建立DTO
Models/DTOs/Requests新增TokenRequest.cs,做為刷新token的Request。
AuthManagementController
注入TokenValidationParameters。
新增Method驗證並重新產生Token
新增VerifyAndGenerateToken方法,在驗證Token參數後,呼叫GenerateJwtToken方法,產生新Token並回傳。
程式碼如下:
新增Method做為刷新Token用
新增RefreshToken方法,做為刷新Token的API接口。
呼叫VerifyAndGenerateToken方法來驗證輸入的Token參數與回傳刷新的Token。
程式碼如下:
呼叫API產生Token與驗證
執行傳案後,以Postman呼叫/api/AuthManagement/Login,來登入並取得Token與RefreshToken。
Body內容為:
執行畫面:
若要刷新產生新的Token,呼叫/api/AuthManagement/RefreshToken,來刷新Token。
執行畫面:
呼叫掛有[Authorize]驗證的API,在Postman的Authorization中,選擇Tyep為Bearer Token,並輸入Token。
執行畫面:
HttpClient呼叫API
在C#中使用HttpClient呼叫API時,設定Header的驗證Token可使用: