<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        asp net core 2.1中如何使用jwt(從原理到精通)

        來源:懂視網(wǎng) 責編:小采 時間:2020-11-27 22:34:47
        文檔

        asp net core 2.1中如何使用jwt(從原理到精通)

        asp net core 2.1中如何使用jwt(從原理到精通):為什么使用 Jwt 最近,移動開發(fā)的勁頭越來越足,學校搞的各種比賽都需要用手機 APP 來撐場面,所以,作為寫后端的,很有必要改進一下以往的基于 Session 的身份認證方式了,理由如下: 移動端經(jīng)常要保持長時間(1 到 2 星期)在線,但是 Session
        推薦度:
        導讀asp net core 2.1中如何使用jwt(從原理到精通):為什么使用 Jwt 最近,移動開發(fā)的勁頭越來越足,學校搞的各種比賽都需要用手機 APP 來撐場面,所以,作為寫后端的,很有必要改進一下以往的基于 Session 的身份認證方式了,理由如下: 移動端經(jīng)常要保持長時間(1 到 2 星期)在線,但是 Session

        為什么使用 Jwt

        最近,移動開發(fā)的勁頭越來越足,學校搞的各種比賽都需要用手機 APP 來撐場面,所以,作為寫后端的,很有必要改進一下以往的基于 Session 的身份認證方式了,理由如下:

      1. 移動端經(jīng)常要保持長時間(1 到 2 星期)在線,但是 Session 卻不好在服務端保存這么久,雖然可以持久化到數(shù)據(jù)庫,但是還是挺費資源
      2. 移動端往往不是使用的網(wǎng)頁技術,所以藏在 Cookie 里面的 SessionId 不是很方便的傳遞給服務端
      3. 服務端暴露給客戶端的接口往往是 RESTful 風格的,這是一種無狀態(tài)的 API 風格,所以身份認證的方式最好也是無狀態(tài)的才好
      4. 所以我選擇了使用 Jwt (Json Web Token) 這個技術。Jwt 是一種無狀態(tài)的分布式的身份驗證方式,與 Session 相反,Jwt 將用戶信息存放在 Token 的 payload 字段保存在客戶端,通過 RSA 加密的方式,保證數(shù)據(jù)不會被篡改,驗證數(shù)據(jù)有效性。

        下面是一個使用 Jwt 的系統(tǒng)的身份驗證流程:

        可以看出,用戶的信息保存在 Token 中,而 Token 分布在用戶的設備中,所以服務端不再需要在內存中保存用戶信息了
        身份認證的 Token 傳遞時以一種相當簡單的格式保存在 header 中,方便客戶端對其進行操作

        原理

        jwt對所有語言都是通用的,只要知道秘鑰,另一一種語言有可以對jwt的有效性進行判斷;

        jwt的組成;Header部分Base64轉化.Payload部分Base64轉化.使用HS256方式根據(jù)秘鑰對前面兩部分進行加密后再Base64轉化,其中使用的hs256加密是header部分指定的,也可以通過官網(wǎng)的查看,如下圖:

        原理就這么簡單,那究竟用怎樣使用C#來實現(xiàn)呢,又怎么確定它的正確性呢?,請繼續(xù)

        使用C#實現(xiàn)

        我們定義一個今天方法,其中需要使用到Microsoft.IdentityModel.Tokens.dll,asp.net core 2.1再帶,如果其他版本,沒有自帶,需要nuget 一下這個類庫

        /// <summary>
         /// 創(chuàng)建jwttoken,源碼自定義
         /// </summary>
         /// <param name="payLoad"></param>
         /// <param name="header"></param>
         /// <returns></returns>
         public static string CreateToken(Dictionary<string, object> payLoad,int expiresMinute, Dictionary<string, object> header = null)
         {
         if (header == null)
         {
         header = new Dictionary<string, object>(new List<KeyValuePair<string, object>>() {
         new KeyValuePair<string, object>("alg", "HS256"),
         new KeyValuePair<string, object>("typ", "JWT")
         });
         }
         //添加jwt可用時間(應該必須要的)
         var now = DateTime.UtcNow;
         payLoad["nbf"] = ToUnixEpochDate( now);//可用時間起始
         payLoad["exp"] = ToUnixEpochDate(now.Add(TimeSpan.FromMinutes(expiresMinute)));//可用時間結束
        
         var encodedHeader = Base64UrlEncoder.Encode(JsonConvert.SerializeObject(header));
         var encodedPayload = Base64UrlEncoder.Encode(JsonConvert.SerializeObject(payLoad));
        
         var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(securityKey));
         var encodedSignature = Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(encodedHeader, ".", encodedPayload))));
        
         var encodedJwt = string.Concat(encodedHeader, ".", encodedPayload, ".", encodedSignature);
         return encodedJwt;
         }
         public static long ToUnixEpochDate(DateTime date) => (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);

        該方法很簡單,只需要傳入header鍵值對和payLoad鍵值對,然后根據(jù)原理進行Base64轉換和hs256加密,接下來我們來使用一個測試類對其進行測試,代碼如下:

        [TestMethod]
         public void TokenValidateTest()
         {
         Dictionary<string, object> payLoad = new Dictionary<string, object>();
         payLoad.Add("sub", "rober");
         payLoad.Add("jti", "09e572c7-62d0-4198-9cce-0915d7493806");
         payLoad.Add("nbf", null);
         payLoad.Add("exp", null);
         payLoad.Add("iss", "roberIssuer");
         payLoad.Add("aud", "roberAudience");
         payLoad.Add("age", 30);
        
         var encodeJwt = TokenContext.CreateToken(payLoad, 30);
        
         var result = TokenContext.Validate(encodeJwt, (load) => { return true; });
         Assert.IsTrue(result);
         }

        先不管后面的驗證,我們先看看其中生成的encodeJwt的值:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJyb2JlciIsImp0aSI6IjY0OWMyYjUxLTE4ZGQtNDEzYy05Yzc5LTI4NWNhMDAxODU2NSIsIm5iZiI6MTU0MDYxMDY2NSwiZXhwIjoxNTQwNjEyNDY1LCJpc3MiOiJyb2Jlcklzc3VlciIsImF1ZCI6InJvYmVyQXVkaWVuY2UiLCJhZ2UiOjMwfQ.7Is2KYHAtSr5fW2gPU1jGeHPzz2ULCZJGcWb40LSYyw

        第一部分和第二部分,并不是加密,只是Base64轉換,我們可以通過其他語言輕松轉換回來,如下使用javascript進行轉,window.atob(base64加密) window.btoa(base64解密)

        var header=JSON.parse(window.atob('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'))

        如下圖:

        我再對payLoa進行轉換回來, var payLoad=JSON.parse(window.atob('eyJzdWIiOiJyb2JlciIsImp0aSI6IjY0OWMyYjUxLTE4ZGQtNDEzYy05Yzc5LTI4NWNhMDAxODU2NSIsIm5iZiI6MTU0MDYxMDY2NSwiZXhwIjoxNTQwNjEyNDY1LCJpc3MiOiJyb2Jlcklzc3VlciIsImF1ZCI6InJvYmVyQXVkaWVuY2UiLCJhZ2UiOjMwfQ')) ,如下圖:

        所以,從這里可以看出來,Base64并不是屬于加密,只是簡單轉換,因此,不能在payLoad中存放重要內容,比如密碼等

        使用aspnetcore 中自帶的類生成jwt

        aspnet core中自帶了一個jwt幫助類,其實原理一樣,對上面做了封裝,豐富了一個內容,我們繼續(xù)使用一個靜態(tài)方法,如下

        /// <summary>
         /// 創(chuàng)建jwtToken,采用微軟內部方法,默認使用HS256加密,如果需要其他加密方式,請更改源碼
         /// 返回的結果和CreateToken一樣
         /// </summary>
         /// <param name="payLoad"></param>
         /// <param name="expiresMinute">有效分鐘</param>
         /// <returns></returns>
         public static string CreateTokenByHandler(Dictionary<string, object> payLoad, int expiresMinute)
         {
         
         var now = DateTime.UtcNow;
        
         // Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
         // You can add other claims here, if you want:
         var claims = new List<Claim>();
         foreach (var key in payLoad.Keys)
         {
         var tempClaim = new Claim(key, payLoad[key]?.ToString());
         claims.Add(tempClaim);
         }
         
        
         // Create the JWT and write it to a string
         var jwt = new JwtSecurityToken(
         issuer: null,
         audience: null,
         claims: claims,
         notBefore: now,
         expires: now.Add(TimeSpan.FromMinutes(expiresMinute)),
         signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(securityKey)), SecurityAlgorithms.HmacSha256));
         var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
         return encodedJwt;
         }

        它效果和上面一模一樣,如果使用同樣的header 、payload、秘鑰,生成的jwt肯定一樣,這里就不演示了,感興趣的可以自行嘗試;

        aspnetcore中如何使用自定義jwt驗證

        上面講了那么多,只是為了大家更好的理解如何使用jwt進行驗證,那是jwt是如何進行驗證的呢?,如果一個http請求過來,一般jwt攜帶在http請求頭部的Authorization中;先不看如何獲取,先看看他是如何驗證的,我們再定義個靜態(tài)方法,如下:

        /// <summary>
         /// 驗證身份 驗證簽名的有效性,
         /// </summary>
         /// <param name="encodeJwt"></param>
         /// <param name="validatePayLoad">自定義各類驗證; 是否包含那種申明,或者申明的值, </param>
         /// 例如:payLoad["aud"]?.ToString() == "roberAuddience";
         /// 例如:驗證是否過期 等
         /// <returns></returns>
         public static bool Validate(string encodeJwt,Func<Dictionary<string,object>,bool> validatePayLoad)
         {
         var success = true;
         var jwtArr = encodeJwt.Split('.');
         var header = JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlEncoder.Decode(jwtArr[0]));
         var payLoad = JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlEncoder.Decode(jwtArr[1]));
        
         var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(securityKey));
         //首先驗證簽名是否正確(必須的)
         success = success && string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1])))));
         if (!success)
         {
         return success;//簽名不正確直接返回
         }
         //其次驗證是否在有效期內(也應該必須)
         var now = ToUnixEpochDate(DateTime.UtcNow);
         success = success && (now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString()));
        
         //再其次 進行自定義的驗證
         success = success && validatePayLoad(payLoad);
        
         return success;
         }

        其中validatePayLoad 參數(shù)是一個自定義的驗證的Fun,執(zhí)行該Fun方法時會把解密后的payload作為參數(shù)傳入進去

        我們驗證通過分為兩部分,

        第一,必須的(自認為的) 

      5. jwt簽名是否正確,請看以上代碼實現(xiàn) 
      6. jwt是否在可以時間內,請看以上代碼實現(xiàn)
      7. 第二,自定義的(各復雜的,原理就是獲取payLoad 的某個值,然后對這個值進行各種判讀--等于,大于,包含,)  

      8. 該jwt是不是進入黑名單
      9. aud==‘roberAudience'
      10. 我們來通過一個測試類驗證

        [TestMethod]
         public void TokenCustomerValidateTest()
         {
         Dictionary<string, object> payLoad = new Dictionary<string, object>();
         payLoad.Add("sub", "rober");
         payLoad.Add("jti", Guid.NewGuid().ToString());
         payLoad.Add("nbf", null);
         payLoad.Add("exp", null);
         payLoad.Add("iss", "roberIssuer");
         payLoad.Add("aud", "roberAudience");
         payLoad.Add("age", 30);
        
         var encodeJwt = TokenContext.CreateToken(payLoad, 30);
        
         var result = TokenContext.Validate(encodeJwt, (load) => {
         var success = true;
         //驗證是否包含aud 并等于 roberAudience
         success = success&& load["aud"]?.ToString() == "roberAudience";
        
         //驗證age>20等
         int.TryParse(load["age"].ToString(), out int age);
         Assert.IsTrue(age > 30);
         //其他驗證 jwt的標識 jti是否加入黑名單等
        
         return success;
         });
         Assert.IsTrue(result);
         }

        如上面,我們可以把jwt中的payload解析出來,然后進行各種復雜的想要的驗證;

        其實,aspnet core中的基于角色,用戶、策略,自定義策略的驗證就相當這里的自定義驗證,一下章將詳細說明和對比,這里暫時不講解

        看完上面,是不是覺得jwt很簡單就,主要就兩部

      11. 創(chuàng)建jwt;
      12. 驗證jwt;
      13. 完整代碼如下:

        /// <summary>
         /// Token上下文,負責token的創(chuàng)建和驗證
         /// </summary>
         public class TokenContext
         {
         /// <summary>
         /// 秘鑰,可以從配置文件中獲取
         /// </summary>
         public static string securityKey = "GQDstclechengroberbojPOXOYg5MbeJ1XT0uFiwDVvVBrk";
        
         /// <summary>
         /// 創(chuàng)建jwttoken,源碼自定義
         /// </summary>
         /// <param name="payLoad"></param>
         /// <param name="header"></param>
         /// <returns></returns>
         public static string CreateToken(Dictionary<string, object> payLoad,int expiresMinute, Dictionary<string, object> header = null)
         {
         if (header == null)
         {
         header = new Dictionary<string, object>(new List<KeyValuePair<string, object>>() {
         new KeyValuePair<string, object>("alg", "HS256"),
         new KeyValuePair<string, object>("typ", "JWT")
         });
         }
         //添加jwt可用時間(應該必須要的)
         var now = DateTime.UtcNow;
         payLoad["nbf"] = ToUnixEpochDate( now);//可用時間起始
         payLoad["exp"] = ToUnixEpochDate(now.Add(TimeSpan.FromMinutes(expiresMinute)));//可用時間結束
        
         var encodedHeader = Base64UrlEncoder.Encode(JsonConvert.SerializeObject(header));
         var encodedPayload = Base64UrlEncoder.Encode(JsonConvert.SerializeObject(payLoad));
        
         var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(securityKey));
         var encodedSignature = Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(encodedHeader, ".", encodedPayload))));
        
         var encodedJwt = string.Concat(encodedHeader, ".", encodedPayload, ".", encodedSignature);
         return encodedJwt;
         }
        
         /// <summary>
         /// 創(chuàng)建jwtToken,采用微軟內部方法,默認使用HS256加密,如果需要其他加密方式,請更改源碼
         /// 返回的結果和CreateToken一樣
         /// </summary>
         /// <param name="payLoad"></param>
         /// <param name="expiresMinute">有效分鐘</param>
         /// <returns></returns>
         public static string CreateTokenByHandler(Dictionary<string, object> payLoad, int expiresMinute)
         {
         
         var now = DateTime.UtcNow;
        
         // Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
         // You can add other claims here, if you want:
         var claims = new List<Claim>();
         foreach (var key in payLoad.Keys)
         {
         var tempClaim = new Claim(key, payLoad[key]?.ToString());
         claims.Add(tempClaim);
         }
         
        
         // Create the JWT and write it to a string
         var jwt = new JwtSecurityToken(
         issuer: null,
         audience: null,
         claims: claims,
         notBefore: now,
         expires: now.Add(TimeSpan.FromMinutes(expiresMinute)),
         signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(securityKey)), SecurityAlgorithms.HmacSha256));
         var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
         return encodedJwt;
         }
        
         /// <summary>
         /// 驗證身份 驗證簽名的有效性,
         /// </summary>
         /// <param name="encodeJwt"></param>
         /// <param name="validatePayLoad">自定義各類驗證; 是否包含那種申明,或者申明的值, </param>
         /// 例如:payLoad["aud"]?.ToString() == "roberAuddience";
         /// 例如:驗證是否過期 等
         /// <returns></returns>
         public static bool Validate(string encodeJwt,Func<Dictionary<string,object>,bool> validatePayLoad)
         {
         var success = true;
         var jwtArr = encodeJwt.Split('.');
         var header = JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlEncoder.Decode(jwtArr[0]));
         var payLoad = JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlEncoder.Decode(jwtArr[1]));
        
         var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(securityKey));
         //首先驗證簽名是否正確(必須的)
         success = success && string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1])))));
         if (!success)
         {
         return success;//簽名不正確直接返回
         }
         //其次驗證是否在有效期內(也應該必須)
         var now = ToUnixEpochDate(DateTime.UtcNow);
         success = success && (now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString()));
        
         //再其次 進行自定義的驗證
         success = success && validatePayLoad(payLoad);
        
         return success;
         }
         /// <summary>
         /// 獲取jwt中的payLoad
         /// </summary>
         /// <param name="encodeJwt"></param>
         /// <returns></returns>
         public static Dictionary<string ,object> GetPayLoad(string encodeJwt)
         {
         var jwtArr = encodeJwt.Split('.');
         var payLoad = JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlEncoder.Decode(jwtArr[1]));
         return payLoad;
         }
         public static long ToUnixEpochDate(DateTime date) => 
         (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);
         }

        聲明:本網(wǎng)頁內容旨在傳播知識,若有侵權等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        asp net core 2.1中如何使用jwt(從原理到精通)

        asp net core 2.1中如何使用jwt(從原理到精通):為什么使用 Jwt 最近,移動開發(fā)的勁頭越來越足,學校搞的各種比賽都需要用手機 APP 來撐場面,所以,作為寫后端的,很有必要改進一下以往的基于 Session 的身份認證方式了,理由如下: 移動端經(jīng)常要保持長時間(1 到 2 星期)在線,但是 Session
        推薦度:
        標簽: 原理 net 2.1
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 色婷婷亚洲一区二区三区| 91天堂素人精品系列全集亚洲| 亚洲人成7777| 嘿嘿嘿视频免费网站在线观看 | 日韩免费视频观看| 99热亚洲色精品国产88| 国产人在线成免费视频| 亚洲福利电影一区二区?| 国产91色综合久久免费分享| 77777_亚洲午夜久久多人| 日本阿v免费费视频完整版| 亚洲国产成人精品无码区在线秒播| 亚洲毛片免费观看| 亚洲精品美女网站| 毛片免费vip会员在线看| 亚洲国产成人精品无码区在线秒播| 免费H网站在线观看的| 亚洲国产系列一区二区三区| 永久免费AV无码网站在线观看| 在线91精品亚洲网站精品成人| 成人亚洲综合天堂| 西西人体免费视频| 久久精品国产亚洲AV无码娇色| 亚洲一区中文字幕在线电影网| 成人无遮挡裸免费视频在线观看 | 最近高清国语中文在线观看免费| 亚洲熟伦熟女专区hd高清| 国产男女猛烈无遮档免费视频网站| 色www免费视频| 国产亚洲一区二区三区在线观看 | 精品久久洲久久久久护士免费| 色一情一乱一伦一视频免费看| 亚洲日本乱码在线观看| 最近最新高清免费中文字幕| 亚洲精品天堂在线观看| 亚洲人成人无码网www国产| 亚洲日韩精品无码专区| 亚洲国产精品自在拍在线播放| 豆国产96在线|亚洲| 亚洲人成无码网站| 免费电影在线观看网站|