一、什麼是JWT
文章參考:https://www.leo96.com/article/detail/55
JSON Web令牌(JWT)是一個開放標準(RFC 7519),它定義 了一種緊湊且自包含的方式,用於在各方之間安全地傳輸資訊作為JSON物件。由於此資訊是經過數字簽名的,因此可以被驗證和信任。可以使用祕密(使用HMAC演算法)或使用RSA或ECDSA的公鑰/私鑰對JWT進行簽名。
二、使用場景
1、授權:這是使用JWT的最常見方案。一旦使用者登入,每個後續請求將包括JWT,從而允許使用者訪問該令牌允許的路由,服務和資源。單一登入是當今廣泛使用JWT的一項功能,因為它的開銷很小並且可以在不同的域中輕鬆使用。
2、資訊交換:JSON Web令牌是在各方之間安全傳輸資訊的好方法。因為可以對JWT進行簽名(例如,使用公鑰/私鑰對),所以您可以確定發件人是他們所說的人。此外,由於簽名是使用標頭和有效負載計算的,因此您還可以驗證內容是否未被篡改。
三、JWT授權流程
四、JWT令牌結構
1、header(頭部)頭部是令牌的第一部分,通常由兩部分組成:令牌的型別(即JWT)和令牌所使用的簽名演算法,如SHA256、HMAC等
2、payload(有效載荷)頭部是令牌的第一部分,通常由兩部分組成:令牌的型別(即JWT)和令牌所使用的簽名演算法,如SHA256、HMAC等
有三種說明型別,預定義宣告、公共宣告和私有宣告。宣告名稱僅是三個字元,因為JWT是緊湊的
- 預定義宣告:包括iss(發出者), exp(到期時間), sub(主題), aud(受眾)等,是推薦的但是不是強制的可以沒有。
- 公共宣告:公共宣告,這個部分可以隨便定義,但是要注意和 IANA JSON Web Token 衝突。
- 私有宣告:這個部分是共享被認定資訊中自定義部分。
3、signature(簽名) 簽名是令牌的第三部分,由header和payload進行64位編碼後再使用加密演算法加密即可
五、程式碼擼起來
樓主用vs2022新建了兩個解決方案,分別是Application.Authorization(用來生成token),Application.WebAPI(用來token授權)
一、生成token
[ApiController] [Route("[controller]")] public class AuthorizationController : ControllerBase { public IConfiguration _configuration { get; } public AuthorizationController(IConfiguration configuration) { _configuration = configuration; } /// <summary> /// 獲取Token /// </summary> /// <param name="userName"></param> /// <param name="pwd"></param> /// <returns></returns> [HttpGet] [Route("GetToken")] public dynamic GetToken(string userName= "xiaohemaio", string pwd= "123456") { // 驗證使用者和密碼應該去查詢資料庫,此處省略 if(userName.Equals("xiaohemaio") && pwd.Equals("123456")) { // 有效載荷,這裡可以自定義寫,儘量避免敏感資訊 Claim[] claims = new Claim[] { new Claim("NickName",userName), new Claim("Role","Admin") }; // 需要加密,需要加密key // NuGet引入:Microsoft.IdentityModel.Tokens SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWTAuthorization:securitykey"])); SigningCredentials creds = new SigningCredentials(key,SecurityAlgorithms.HmacSha256); // NuGet引入:Microsoft.IdentityModel.Tokens.Jwt // 官方規定了7個非強制但建議使用的欄位: // iss(issuer):簽發人 // exp(expiration time) :過期時間 // sub(subject):主題 // aud(audience):受眾 // nbf(not befaore):生效時間 // lat(issued at):簽發時間 // jti(jwt id):編號 JwtSecurityToken token = new JwtSecurityToken( issuer:_configuration["JWTAuthorization:issuer"], audience: _configuration["JWTAuthorization:audience"], claims: claims, expires:System.DateTime.Now.AddMinutes(5), signingCredentials: creds ); string returnToken = new JwtSecurityTokenHandler().WriteToken(token); return Ok(new { Data= returnToken ,Success=true,Msg="Token生成成功"}); } return Ok(new { Data = string.Empty, Success = false, Msg = "Token生成失敗" }); } }
"JWTAuthorization": { "issuer": "xiaohemaio", // 簽發人,可自定義 "audience": "xiaohemiao", // 受眾,可自定義 "securitykey": "8cbe2b73be20b183bd787f31d4dc3f0d05bb2640495ebf8f52e790907d20f70a" // 加密key,根據需要自己生成 參考地址 https://crypot.51strive.com/sha256.html }
二、Token授權
[ApiController] [Route("[controller]")] public class AuthorizationController : ControllerBase { [HttpGet] [Route("Get")] public dynamic Get() { return Ok(new { Data = "test", Sueccess = true }); } [HttpGet] [Route("GetAuthorizationData")] [Authorize] public dynamic GetAuthorizationData() { // 獲取當前登入的使用者名稱 var userName = HttpContext.AuthenticateAsync().Result.Principal.Claims.FirstOrDefault(x => x.Type.Equals("NickName"))?.Value; return new JsonResult(new { Data = userName, Sueccess = true }); } }
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(); { // ************************2、JWT鑑權授權****************************************** // NuGet引入程式包:Microsoft.AspNetCore.Authentication.JwtBearer (如果是.net5則使用5.0及以上的版本,如是.net6 則使用6.0及以上版本,如是.net core 3.1 則使用3.0及以上版本) services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey= true, ValidIssuer= Configuration["JWTAuthorization:issuer"], // Issuer 這個和應用Application.Authorization裡面的設定一樣,表示誰簽發的Token ValidAudience = Configuration["JWTAuthorization:audience"], // Audience 這個和應用Application.Authorization裡面的設定一樣,表示受眾的Token IssuerSigningKey =new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWTAuthorization:securitykey"])), // 拿到securitykey AudienceValidator = (m,n,z) => { // 自定義規則 return true; } }; }); } } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); // ********************1、啟用鑑權********************* app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } }
"JWTAuthorization": { "issuer": "xiaohemaio", // 簽發人,可自定義 "audience": "xiaohemiao", // 受眾,可自定義 "securitykey": "8cbe2b73be20b183bd787f31d4dc3f0d05bb2640495ebf8f52e790907d20f70a" // 加密key,根據需要自己生成 參考地址 https://crypot.51strive.com/sha256.html }