第二十八節:Asp.Net Core中JWT的幾種寫法和認證方式

一. 前言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
Base64編碼和解碼
 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     }
JwtData

封裝加密和解密方法

 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     }
JWTHelp

測試

 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
View Code

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     }
View Code

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);
        }
    }
View Code

前端頁面測試代碼

 

 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             });
View Code

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

 

 

 

!

  • 做       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 本人才疏學淺,用郭德綱的話說「我是一個小學生」,若有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文連接或在文章開頭加上本人博客地址,不然保留追究法律責任的權利。
相關文章
相關標籤/搜索