一. 前言html
1.說明前端
本章節重點介紹JWT的利用不一樣程序集的幾種寫法及認證方式,而後複習一下JWT的組成。ajax
其餘概念參考:http://www.javashuo.com/article/p-hkcvxebb-bq.html算法
官網:https://jwt.iojson
2.JWT組成安全
樣式:"xxxxxxxxxxxx.xxxxxxxxxxxxx.xxxxxxxxxxxxxxxx"由三部分組成.app
(1).Header頭部:{\"alg\":\"HS256\",\"typ\":\"JWT\"}基本組成,也能夠本身添加別的內容,而後對最後的內容進行Base64編碼.ide
(2).Payload負載:iss、sub、aud、exp、nbf、iat、jti基本參數,也能夠本身添加別的內容,而後對最後的內容進行Base64編碼.測試
(3).Signature簽名:將Base64後的Header和Payload經過.組合起來,而後利用Hmacsha256+密鑰進行加密。this
二. 加解密幾種寫法
1. 寫法1
說明:利用規則本身手動封裝,安裝【NETCore.Encrypt】程序集,利用裏面的HMAC加密算法,聲明一個expire用於存放過時時間。校驗的時候先驗證時間是否過時,再驗證簽名的準確性。
詳細代碼見:TestJwt1
1 #region Base64編碼 2 /// <summary> 3 /// Base64編碼 4 /// </summary> 5 /// <param name="text">待編碼的文本字符串</param> 6 /// <returns>編碼的文本字符串</returns> 7 public string Base64UrlEncode(string text) 8 { 9 var plainTextBytes = Encoding.UTF8.GetBytes(text); 10 var base64 = Convert.ToBase64String(plainTextBytes).Replace('+', '-').Replace('/', '_').TrimEnd('='); 11 return base64; 12 } 13 #endregion 14 15 #region Base64解碼 16 /// <summary> 17 /// Base64解碼 18 /// </summary> 19 /// <param name="base64UrlStr"></param> 20 /// <returns></returns> 21 22 public string Base64UrlDecode(string base64UrlStr) 23 { 24 base64UrlStr = base64UrlStr.Replace('-', '+').Replace('_', '/'); 25 switch (base64UrlStr.Length % 4) 26 { 27 case 2: 28 base64UrlStr += "=="; 29 break; 30 case 3: 31 base64UrlStr += "="; 32 break; 33 } 34 var bytes = Convert.FromBase64String(base64UrlStr); 35 return Encoding.UTF8.GetString(bytes); 36 } 37 #endregion
1 /// <summary> 2 /// 手寫JWT算法 3 /// </summary> 4 public bool TestJwt1() 5 { 6 string secretKey = Configuration["SecretKey"]; 7 //1.加密 8 //1.1 表頭的處理 9 string headerBase64Url = this.Base64UrlEncode("{\"alg\":\"HS256\",\"typ\":\"JWT\"}"); 10 //1.2 PayLoad的處理 11 var jwtPayLoad = new 12 { 13 expire = DateTime.Now.AddMinutes(15), 14 userId = "00000000001", 15 userAccount = "admin" 16 }; 17 string payloadBase64Url = this.Base64UrlEncode(JsonConvert.SerializeObject(jwtPayLoad)); 18 //1.3 Sign的處理 19 string sign = $"{headerBase64Url}.{payloadBase64Url}".HMACSHA256(secretKey); 20 //1.4 最終的jwt字符串 21 string jwtStr = $"{headerBase64Url}.{payloadBase64Url}.{sign}"; 22 23 //2.校驗token是否正確 24 bool result; //True表示經過,False表示未經過 25 //2.1. 獲取token中的PayLoad中的值,並作過時校驗 26 JwtData myData = JsonConvert.DeserializeObject<JwtData>(this.Base64UrlDecode(jwtStr.Split('.')[1])); //這一步已經獲取到了payload中的值,並進行轉換了 27 var nowTime = DateTime.Now; 28 if (nowTime > myData.expire) 29 { 30 //表示token過時,校驗未經過 31 result = false; 32 return result; 33 } 34 else 35 { 36 //2.2 作準確性校驗 37 var items = jwtStr.Split('.'); 38 var oldSign = items[2]; 39 string newSign = $"{items[0]}.{items[1]}".HMACSHA256(secretKey); 40 result = oldSign == newSign; //true表示檢驗經過,false表示檢驗未經過 41 return result; 42 } 43 }
2. 寫法2(推薦!)
說明:使用官方JWT程序集【JWT 5.3.1】,封裝加密和解密算法,詳見:JWTHelp幫助類.其中加密算法的封裝將extraHeaders參數做爲一個可空參數,能夠根據本身的須要決定是否在Header頭中添加額外的參數。
jwt實體類
1 public class JwtData 2 { 3 public DateTime expire { get; set; } //表明過時時間 4 5 public string userId { get; set; } 6 7 public string userAccount { get; set; } 8 }
封裝加密和解密方法
1 /// <summary> 2 /// Jwt的加密和解密 3 /// 注:加密和加密用的是用一個密鑰 4 /// 依賴程序集:【JWT】 5 /// </summary> 6 public class JWTHelp 7 { 8 9 /// <summary> 10 /// JWT加密算法 11 /// </summary> 12 /// <param name="payload">負荷部分,存儲使用的信息</param> 13 /// <param name="secret">密鑰</param> 14 /// <param name="extraHeaders">存放表頭額外的信息,不須要的話能夠不傳</param> 15 /// <returns></returns> 16 public static string JWTJiaM(IDictionary<string, object> payload, string secret, IDictionary<string, object> extraHeaders = null) 17 { 18 IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); 19 IJsonSerializer serializer = new JsonNetSerializer(); 20 IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); 21 IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); 22 var token = encoder.Encode(payload, secret); 23 return token; 24 } 25 26 /// <summary> 27 /// JWT解密算法 28 /// </summary> 29 /// <param name="token">須要解密的token串</param> 30 /// <param name="secret">密鑰</param> 31 /// <returns></returns> 32 public static string JWTJieM(string token, string secret) 33 { 34 try 35 { 36 IJsonSerializer serializer = new JsonNetSerializer(); 37 IDateTimeProvider provider = new UtcDateTimeProvider(); 38 IJwtValidator validator = new JwtValidator(serializer, provider); 39 IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); 40 IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder); 41 var json = decoder.Decode(token, secret, true); 42 //校驗經過,返回解密後的字符串 43 return json; 44 } 45 catch (TokenExpiredException) 46 { 47 //表示過時 48 return "expired"; 49 } 50 catch (SignatureVerificationException) 51 { 52 //表示驗證不經過 53 return "invalid"; 54 } 55 catch (Exception) 56 { 57 return "error"; 58 } 59 } 60 61 62 }
測試
1 /// <summary> 2 /// 利用JWT官方程序集的寫法 3 /// </summary> 4 public void TestJwt2() 5 { 6 string secretKey = Configuration["SecretKey"]; 7 8 //1.加密 9 //1.1 額外的header參數也能夠不設置 10 var extraHeaders = new Dictionary<string, object> 11 { 12 {"myName", "limaru" }, 13 }; 14 //過時時間(能夠不設置,下面表示簽名後 20分鐘過時) 15 double exp = (DateTime.UtcNow.AddMinutes(20) - new DateTime(1970, 1, 1)).TotalSeconds; 16 //進行組裝 17 var payload = new Dictionary<string, object> 18 { 19 {"userId", "00000000001" }, 20 {"userAccount", "admin" }, 21 {"exp",exp } 22 }; 23 24 //1.2 進行JWT簽名 25 var token = JWTHelp.JWTJiaM(payload, secretKey, extraHeaders); 26 27 //2. 解密 28 var result = JWTHelp.JWTJieM(token, secretKey); 29 //而後在轉換一下 30 JwtData myData = JsonConvert.DeserializeObject<JwtData>(result); 31 32 }
3. 寫法3
說明:使用Identity家的程序集【System.IdentityModel.Tokens.Jwt】,進行加密和解密,詳見:TestJwt3。
注:下面代碼,解密的時候不驗證 aud 和 iss, ClockSkew = TimeSpan.Zero 表明校驗過時時間的偏移量,即驗證過時時間:(expires+該值),該值默認爲5min,這裏設置爲0,表示生成token時的expries即爲過時時間 。
1 public bool TestJwt3() 2 { 3 string secretKey = Configuration["SecretKey"]; 4 string token; 5 //加密 6 { 7 var tokenHandler = new JwtSecurityTokenHandler(); 8 var key = Encoding.Default.GetBytes(secretKey); 9 var tokenDescriptor = new SecurityTokenDescriptor() 10 { 11 Subject = new ClaimsIdentity(new Claim[] { 12 new Claim("userId","00000000001"), 13 new Claim("userAccount","admin") 14 }), 15 Expires = DateTime.UtcNow.AddSeconds(10), 16 SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) 17 }; 18 token = tokenHandler.WriteToken(tokenHandler.CreateToken(tokenDescriptor)); //將組裝好的格式生成加密後的jwt字符串 19 } 20 //解密 21 bool result; 22 { 23 var tokenHandler = new JwtSecurityTokenHandler(); 24 var key = Encoding.Default.GetBytes(secretKey); 25 var validationParameters = new TokenValidationParameters 26 { 27 ValidateAudience = false, //表示不驗證aud 28 ValidateIssuer = false, //表示不驗證iss 29 IssuerSigningKey = new SymmetricSecurityKey(key), 30 ClockSkew = TimeSpan.Zero //表明校驗過時時間的偏移量,即驗證過時時間:(expires+該值),該值默認爲5min,這裏設置爲0,表示生成token時的expries即爲過時時間 31 }; 32 SecurityToken validatedToken; //解密後的對象 33 try 34 { 35 ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(token, validationParameters, out validatedToken); 36 result = true; 37 //獲取payload中的數據 38 var jwtPayload = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson(); ; 39 } 40 catch (SecurityTokenExpiredException) 41 { 42 //表示過時 43 result = false; 44 } 45 catch (SecurityTokenException) 46 { 47 //表示token錯誤 48 result = false; 49 } 50 } 51 return result; 52 }
三. 校驗的幾種方式
1. 利用過濾器校驗
這裏使用override這個方法OnActionExecuting,在action執行以前過濾。
(1).涉及到幾個技術點:
A.判斷aciton是否有某個特性:
context.ActionDescriptor.EndpointMetadata.Any(x => x.GetType() == typeof(SkipAttribute));
B.判斷是不是ajax請求:
判斷Headers["X-Requested-With"]的值是否是"XMLHttpRequest".
C.獲取傳遞過來的參數:
a. ajax放在Header中傳遞的參數:context.HttpContext.Request.Headers["auth"].ToString(); 判空方式:token == "null" || string.IsNullOrEmpty(token)
b. 經過href=xxx?auth=xx傳遞的參數:context.HttpContext.Request.Query["auth"].ToString(); 判空形式:string.IsNullOrEmpty(token)
PS:如今有一種Bearer認證, 是這樣傳遞的("Authorization" "Bearer token"), 獲取方式同上面的a,可是要拿到token的值,還須要截取一下,詳見代碼xxxx
D.過濾器中截斷返回的幾種形式:
a.非ajax的截斷:直接跳轉到某個未受權的頁面,如:context.Result = new RedirectResult("/Admin/ErrorIndex?isLogin=noPer");
b.ajax的截斷:
①.返回JsonResult,進入ajax中的success回調: context.Result = new JsonResult(new { status = "error", msg = "非法請求,參數已通過期" });
②.只返回狀態碼,進入ajax中的error回調:context.Result = new StatusCodeResult(401); 或 context.HttpContext.Response.StatusCode = 401;
③.返回ContentResult,進入ajax的error回調,同時回傳錯誤內容:context.Result = new ContentResult { Content = "沒有權限哦", StatusCode = 401 };
注:推薦上述③,由於能夠和正常的請求返回完全區分開,特別注意過濾器中要加return; 光context.Result不能截斷.。
E.過濾器中傳值和action中取值:
a.傳值:context.RouteData.Values.Add("auth", xxxx);
b.取值:ControllerContext.RouteData.Values["auth"].ToString()
(2).實戰測試
A:auth認證,指Header中傳遞參數的時候("auth", token),對於ajax返回JsonResult,校驗不經過的時候,進入的是ajax中的success回調.
B:Bearer認證,說白了就是在Header中傳遞參數的時候("Authorization", "Bearer " + token),在值的前面加了一個Bearer和空格,而後在解析的時候須要隔離拿出來token值.
PS:在JwtCheck2中,對於ajax請求驗證未經過的時候返回ContextResult,狀態碼爲401,進入ajax的error回調中,非ajax請求和A相似。
服務端方法:獲取token的代碼、auth認證接口、Bearer認證接口、沒有權限的頁面
1 #region 獲取Token 2 /// <summary> 3 /// 獲取Token 4 /// </summary> 5 /// <returns></returns> 6 public String GetToken() 7 { 8 string secretKey = Configuration["SecretKey"]; 9 //1.加密 10 //1.1 額外的header參數也能夠不設置 11 var extraHeaders = new Dictionary<string, object> 12 { 13 {"myName", "limaru" }, 14 }; 15 //過時時間(能夠不設置,下面表示簽名後 20分鐘過時) 16 double exp = (DateTime.UtcNow.AddMinutes(20) - new DateTime(1970, 1, 1)).TotalSeconds; 17 //進行組裝 18 var payload = new Dictionary<string, object> 19 { 20 {"userId", "00000000001" }, 21 {"userAccount", "admin" }, 22 {"exp",exp } 23 }; 24 25 //1.2 進行JWT簽名 26 var token = JWTHelp.JWTJiaM(payload, secretKey, extraHeaders); 27 return token; 28 } 29 #endregion 30 31 #region JwtCheck1校驗(auth認證) 32 [TypeFilter(typeof(JwtCheck1))] 33 public IActionResult GetMsg1() 34 { 35 36 var jwtData = JsonConvert.DeserializeObject<JwtData>(ControllerContext.RouteData.Values["auth"].ToString()); 37 return Json(new { status = "ok", msg = jwtData.userId }); 38 } 39 #endregion 40 41 #region JwtCheck2校驗(Bearer認證) 42 [TypeFilter(typeof(JwtCheck2))] 43 public IActionResult GetMsg2() 44 { 45 var jwtData = JsonConvert.DeserializeObject<JwtData>(ControllerContext.RouteData.Values["auth"].ToString()); 46 return Json(new { status = "ok", msg = jwtData.userId }); 47 } 48 49 #endregion
auth認證過濾器,對於ajax返回的是JsonResult,進入ajax的success
1 /// <summary> 2 /// auth認證過濾器,進入ajax的success 3 /// </summary> 4 public class JwtCheck1 : ActionFilterAttribute 5 { 6 7 private IConfiguration _configuration; 8 public JwtCheck1(IConfiguration configuration) 9 { 10 _configuration = configuration; 11 } 12 13 /// <summary> 14 /// action執行前執行 15 /// </summary> 16 /// <param name="context"></param> 17 public override void OnActionExecuting(ActionExecutingContext context) 18 { 19 //1.判斷是否須要校驗 20 var isSkip = context.ActionDescriptor.EndpointMetadata.Any(x => x.GetType() == typeof(SkipAttribute)); 21 if (isSkip == false) 22 { 23 //2. 判斷是什麼請求(ajax or 非ajax) 24 var actionContext = context.HttpContext; 25 if (IsAjaxRequest(actionContext.Request)) 26 { 27 //表示是ajax 28 var token = context.HttpContext.Request.Headers["auth"].ToString(); //ajax請求傳過來 29 if (token == "null" || string.IsNullOrEmpty(token)) 30 { 31 context.Result = new JsonResult(new { status = "error", msg = "非法請求,參數爲空" }); 32 return; 33 } 34 //校驗auth的正確性 35 var result = JWTHelp.JWTJieM(token, _configuration["SecretKey"]); 36 if (result == "expired") 37 { 38 context.Result = new JsonResult(new { status = "error", msg = "非法請求,參數已通過期" }); 39 return; 40 } 41 else if (result == "invalid") 42 { 43 context.Result = new JsonResult(new { status = "error", msg = "非法請求,未經過校驗" }); 44 return; 45 } 46 else if (result == "error") 47 { 48 context.Result = new JsonResult(new { status = "error", msg = "非法請求,未經過校驗" }); 49 return; 50 } 51 else 52 { 53 //表示校驗經過,用於向控制器中傳值 54 context.RouteData.Values.Add("auth", result); 55 } 56 57 } 58 else 59 { 60 //表示是非ajax請求,則auth拼接在參數中傳過來 61 var token = actionContext.Request.Query["auth"].ToString(); 62 if (token == "null" || string.IsNullOrEmpty(token)) 63 { 64 context.Result = new RedirectResult("/Home/NoPerIndex?reason=null"); 65 return; 66 } 67 //校驗auth的正確性 68 var result = JWTHelp.JWTJieM(token, _configuration["SecretKey"]); 69 if (result == "expired") 70 { 71 context.Result = new RedirectResult("/Home/NoPerIndex?reason=expired"); 72 return; 73 } 74 else if (result == "invalid") 75 { 76 context.Result = new RedirectResult("/Home/NoPerIndex?reason=invalid"); 77 return; 78 } 79 else if (result == "error") 80 { 81 context.Result = new RedirectResult("/Home/NoPerIndex?reason=error"); 82 return; 83 } 84 else 85 { 86 //表示校驗經過,用於向控制器中傳值 87 context.RouteData.Values.Add("auth", result); 88 } 89 } 90 } 91 92 } 93 94 /// <summary> 95 /// 判斷該請求是不是ajax請求 96 /// </summary> 97 /// <param name="request"></param> 98 /// <returns></returns> 99 private bool IsAjaxRequest(HttpRequest request) 100 { 101 string header = request.Headers["X-Requested-With"]; 102 return "XMLHttpRequest".Equals(header); 103 } 104 }
Bearer認證過濾器,對於ajax返回的是ContentResult,進入的是ajax的error
/// <summary> /// Bearer認證,返回ajax中的error /// </summary> public class JwtCheck2 : ActionFilterAttribute { private IConfiguration _configuration; public JwtCheck2(IConfiguration configuration) { _configuration = configuration; } /// <summary> /// action執行前執行 /// </summary> /// <param name="context"></param> public override void OnActionExecuting(ActionExecutingContext context) { //1.判斷是否須要校驗 var isSkip = context.ActionDescriptor.EndpointMetadata.Any(x => x.GetType() == typeof(SkipAttribute)); if (isSkip == false) { //2. 判斷是什麼請求(ajax or 非ajax) var actionContext = context.HttpContext; if (IsAjaxRequest(actionContext.Request)) { //表示是ajax var token = context.HttpContext.Request.Headers["Authorization"].ToString(); //ajax請求傳過來 string pattern = "^Bearer (.*?)$"; if (!Regex.IsMatch(token, pattern)) { context.Result = new ContentResult { StatusCode = 401, Content = "token格式不對!格式爲:Bearer {token}" }; return; } token = Regex.Match(token, pattern).Groups[1]?.ToString(); if (token == "null" || string.IsNullOrEmpty(token)) { context.Result = new ContentResult { StatusCode = 401, Content = "token不能爲空" }; return; } //校驗auth的正確性 var result = JWTHelp.JWTJieM(token, _configuration["SecretKey"]); if (result == "expired") { context.Result = new ContentResult { StatusCode = 401, Content = "expired" }; return; } else if (result == "invalid") { context.Result = new ContentResult { StatusCode = 401, Content = "invalid" }; return; } else if (result == "error") { context.Result = new ContentResult { StatusCode = 401, Content = "error" }; return; } else { //表示校驗經過,用於向控制器中傳值 context.RouteData.Values.Add("auth", result); } } else { //表示是非ajax請求,則auth拼接在參數中傳過來 var token = actionContext.Request.Query["Authorization"].ToString(); if (token == "null" || string.IsNullOrEmpty(token)) { context.Result = new RedirectResult("/Home/NoPerIndex?reason=null"); return; } string pattern = "^Bearer (.*?)$"; if (!Regex.IsMatch(token, pattern)) { context.Result = new RedirectResult("/Home/NoPerIndex?reason=token格式不對!格式爲:Bearer {token}"); return; } token = Regex.Match(token, pattern).Groups[1]?.ToString(); if (token == "null" || string.IsNullOrEmpty(token)) { context.Result = new RedirectResult("/Home/NoPerIndex?reason=token不能爲空"); return; } //校驗auth的正確性 var result = JWTHelp.JWTJieM(token, _configuration["SecretKey"]); if (result == "expired") { context.Result = new RedirectResult("/Home/NoPerIndex?reason=expired"); return; } else if (result == "invalid") { context.Result = new RedirectResult("/Home/NoPerIndex?reason=invalid"); return; } else if (result == "error") { context.Result = new RedirectResult("/Home/NoPerIndex?reason=error"); return; } else { //表示校驗經過,用於向控制器中傳值 context.RouteData.Values.Add("auth", result); } } } } /// <summary> /// 判斷該請求是不是ajax請求 /// </summary> /// <param name="request"></param> /// <returns></returns> private bool IsAjaxRequest(HttpRequest request) { string header = request.Headers["X-Requested-With"]; return "XMLHttpRequest".Equals(header); } }
前端頁面測試代碼
1 //獲取token 2 $("#j_btn1").click(function () { 3 $.ajax({ 4 url: "/Home/GetToken", 5 type: "Get", 6 data: {}, 7 datatype: "json", 8 success: function (data) { 9 console.log(data); 10 window.localStorage.setItem("token", data); 11 alert("獲取成功"); 12 } 13 }); 14 }); 15 //2.測試校驗(auth驗證-ajax) 16 $("#j_btn2").click(function () { 17 var token = window.localStorage.getItem("token"); 18 $.ajax({ 19 url: "/Home/GetMsg1", 20 type: "Get", 21 data: {}, 22 datatype: "json", 23 //設置header的方式1 24 //headers: { "auth": token }, 25 //設置header的方式2 26 beforeSend: function (xhr) { 27 xhr.setRequestHeader("auth", token); 28 }, 29 success: function (data) { 30 if (data.status == "ok") { 31 alert(data.msg); 32 } else { 33 alert(data.msg); 34 } 35 } 36 }); 37 }); 38 39 //3.測試校驗(auth驗證-非ajax) 40 $("#j_btn3").click(function () { 41 var token = window.localStorage.getItem("token"); 42 window.location.href = "/Home/GetMsg1?auth=" + token; 43 }); 44 45 //4.測試校驗(Bearer驗證-ajax) 46 $("#j_btn4").click(function () { 47 var token = window.localStorage.getItem("token"); 48 $.ajax({ 49 url: "/Home/GetMsg2", 50 type: "Get", 51 data: {}, 52 datatype: "json", 53 //設置header的方式1 54 //headers: { "auth": token }, 55 //設置header的方式2 56 beforeSend: function (xhr) { 57 xhr.setRequestHeader("Authorization", "Bearer " + token); 58 }, 59 success: function (data) { 60 if (data.status == "ok") { 61 alert(data.msg); 62 } else { 63 alert(data.msg); 64 } 65 }, 66 //當安全校驗未經過的時候進入這裏 67 error: function (xhr) { 68 if (xhr.status == 401) { 69 console.log(xhr.responseText); 70 alert(xhr.responseText) 71 } 72 } 73 }); 74 }); 75 76 //5.測試校驗(Bearer驗證-非ajax) 77 $("#j_btn5").click(function () { 78 var token = window.localStorage.getItem("token"); 79 window.location.href = "/Home/GetMsg2?Authorization=Bearer " + token; 80 });
2. 利用中間件校驗
認證依賴程序集:【Microsoft.AspNetCore.Authentication.JwtBearer】,在ConfigureService進行jwt的註冊,而後在Configure中使用 app.UseAuthentication();進行全局認證。
服務端方法:獲取token的代碼、認證接口
1 /// <summary> 2 /// 獲取Token 3 /// </summary> 4 /// <returns></returns> 5 public String GetToken2() 6 { 7 string secretKey = Configuration["SecretKey"]; 8 string token; 9 //加密 10 { 11 var tokenHandler = new JwtSecurityTokenHandler(); 12 var key = Encoding.Default.GetBytes(secretKey); 13 var tokenDescriptor = new SecurityTokenDescriptor() 14 { 15 Subject = new ClaimsIdentity(new Claim[] { 16 new Claim("userId","00000000001"), 17 new Claim("userAccount","admin") 18 }), 19 Expires = DateTime.UtcNow.AddSeconds(10), 20 SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) 21 }; 22 token = tokenHandler.WriteToken(tokenHandler.CreateToken(tokenDescriptor)); //將組裝好的格式生成加密後的jwt字符串 23 } 24 return token; 25 26 } 27 /// <summary> 28 /// 獲取信息 29 /// </summary> 30 /// <returns></returns> 31 [Authorize] 32 public string GetMsg3() 33 { 34 return "ok"; 35 }
中間件代碼
1 public void ConfigureServices(IServiceCollection services) 2 { 3 4 //註冊jwt校驗 5 services.AddAuthentication("Bearer").AddJwtBearer(options => 6 { 7 options.TokenValidationParameters = new TokenValidationParameters 8 { 9 ValidateIssuer = false,//是否驗證Issuer 10 ValidateAudience = false,//是否驗證Audience 11 ClockSkew = TimeSpan.Zero,//校驗時間是否過時時,設置的時鐘偏移量(默認是5min,這裏設置爲0,即用的是產生token時設置的國企時間) 12 IssuerSigningKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(Configuration["SecretKey"])),//拿到SecurityKey 13 }; 14 }); 15 16 services.AddControllersWithViews(); 17 }
前端代碼:
1 //下面是基於【System.IdentityModel.Tokens.Jwt】的jwt校驗 2 $("#j_btn6").click(function () { 3 $.ajax({ 4 url: "/Home/GetToken2", 5 type: "Get", 6 data: {}, 7 datatype: "json", 8 success: function (data) { 9 console.log(data); 10 window.localStorage.setItem("token", data); 11 alert("獲取成功"); 12 } 13 }); 14 }); 15 $("#j_btn7").click(function () { 16 var token = window.localStorage.getItem("token"); 17 $.ajax({ 18 url: "/Home/GetMsg3", 19 type: "Get", 20 data: {}, 21 datatype: "json", 22 //設置header的方式1 23 headers: { 24 "Authorization": "Bearer " + token, 25 }, 26 //設置header的方式2 27 //beforeSend: function (xhr) { 28 // xhr.setRequestHeader("Authorization", "Bearer " + token); 29 //}, 30 success: function (data) { 31 alert(data); 32 }, 33 //當安全校驗未經過的時候進入這裏 34 error: function (xhr) { 35 if (xhr.status == 401) { 36 alert("校驗未經過"); 37 } 38 } 39 }); 40 });
其它博客:https://www.cnblogs.com/CreateMyself/p/11123023.html
參考: https://www.jianshu.com/p/be936f1fba95
!