第二十八节:Asp.Net Core中JWT的几种写法和认证方式

一. 前言

1.说明

  本章节重点介绍JWT的利用不同程序集的几种写法及认证方式,然后复习一下JWT的组成。

  其他概念参考:https://www.cnblogs.com/yaopengfei/p/10451189.html

  官网:https://jwt.io

2.JWT组成

  样式:"xxxxxxxxxxxx.xxxxxxxxxxxxx.xxxxxxxxxxxxxxxx"由三部分组成.

(1).Header头部:{"alg":"HS256","typ":"JWT"}基本组成,也可以自己添加别的内容,然后对最后的内容进行Base64编码.

(2).Payload负载:iss、sub、aud、exp、nbf、iat、jti基本参数,也可以自己添加别的内容,然后对最后的内容进行Base64编码.

(3).Signature签名:将Base64后的Header和Payload通过.组合起来,然后利用Hmacsha256+密钥进行加密。

二. 加解密几种写法

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         }

第二十八节:Asp.Net Core中JWT的几种写法和认证方式

 前端代码:

 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

!

 

相关推荐