JWT使用笔记

6 篇文章 0 订阅

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

最近公司在做系统整合, 要将原来一个系统按领域划分成不同系统, 但是登录还是交由门户登录, 考虑各方面后, 最后选择了使用Jwt做系统间交互凭证


一、什么是Jwt?

参考: https://blog.csdn.net/weixin_45070175/article/details/118559272

二、使用步骤

1.引入jwt

System.IdentityModel.Tokens.Jwt
在这里插入图片描述

2.生成jwtToken

代码如下(示例):

SecurityKey securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(txtKey.Text));
            var loginUser = txtUser.Text;
            
            DateTime utcNow = dateTimePicker1.Value;

            string uuid = Guid.NewGuid().ToString();
            var claims = new List<Claim>()
            {
                new Claim("uuid", uuid),
                new Claim(ClaimsName, loginUser),
                new Claim(ClaimTypes.Name, loginUser)
            };
            JwtSecurityToken jwtToken = new JwtSecurityToken(
                issuer: "aaa", //签发人
                claims: claims, //token内容
                notBefore: utcNow, //签发时间
                expires: utcNow.AddHours(4), //过期时间
                signingCredentials: new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256) //加密方式和加密key
            );

            //生成token
            txtToken.Text= new JwtSecurityTokenHandler().WriteToken(jwtToken);

2.解析jwtToken

		    try
            {
            //解析方式1, 不校验token, 直接强制解析, 不推荐使用
                var jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token);
                var jwtPayload = jwtToken.Payload;

                txtJson.Text = ConvertJsonString(JsonHelper.ToJson(jwtToken.Payload));
    			//解析后的内容
                var expDataStr = Convert.ToInt64(jwtPayload["exp"]);
                var iatDataStr = Convert.ToInt64(jwtPayload["iat"]);
				//过期时间
                txtExpData.Text= DateHelper.ToLocalDateTimeText(expDataStr);
                //签发时间
                txtIatTime.Text= DateHelper.ToLocalDateTimeText(iatDataStr);

                //解析方式2, 使用加密key进行校验解析
                SecurityKey securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key));
                //解析模型跟上面生成模型保持一致
                var validateParameter = new TokenValidationParameters()
                {
                    ValidateLifetime = false,
                    ValidateAudience = false,
                    ValidateIssuer = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = "aaa",
                    IssuerSigningKey = securityKey
                };
                SecurityToken securityToken = null;
                var claimsPrincipal = new JwtSecurityTokenHandler().ValidateToken(token, validateParameter, out securityToken);
                //解析后的内容
                jwtPayload = ((JwtSecurityToken)securityToken).Payload;
            }
            catch (SecurityTokenException ex)
            {
                MessageBox.Show("token校验失败"+ex.Message);
            }

3. 具体使用jwt校验

  1. 前端Request发送请求时, 在header中附加上Authorization, 写入jwt-token
    在这里插入图片描述
  2. 后台添加过滤器AuthorizeFilterAttribute,继承AuthorizeAttribute,重写OnAuthorization方法, 在方法中校验jwttoken是否合法, 如果不合法,直接return掉
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace Dji.LMSRule.App.Filters
{
	public class AuthorizeFilterAttribute : AuthorizeAttribute
	{
		private readonly string Authorization = "Authorization";
		private readonly string Bearer = "Bearer ";
		private readonly string ClaimsName = "name";
		/// <summary>
		/// 加密key
		/// </summary>
		private readonly SecurityKey securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("这里是秘钥"));
		public override void OnAuthorization(AuthorizationContext filterContext)
		{
			var token = filterContext.HttpContext.Request.Headers.Get(Authorization);
			if (string.IsNullOrWhiteSpace(token))
			{
				AuthFailResponse(filterContext);
				return;
			}
			string userName = String.Empty;
			try
			{
				//校验token是否有Bearer前缀
				if (token.Length < Bearer.Length || !token.StartsWith(Bearer))
				{
					return;
				}

				token = token.Replace(Bearer, "");
				var validateParameter = new TokenValidationParameters()
				{
					ValidateLifetime = false,
					ValidateAudience = false,
					ValidateIssuer = true,
					ValidateIssuerSigningKey = true,
					ValidIssuer = "aaa",
					IssuerSigningKey = securityKey
				};
				SecurityToken securityToken = null;
				var claimsPrincipal = new JwtSecurityTokenHandler().ValidateToken(token, validateParameter, out securityToken);
				var jwtPayload = ((JwtSecurityToken)securityToken).Payload;

				//这里取出token里的用户名, 如果有需要用的, 可以放到session里
				userName = jwtPayload[ClaimsName] + "";
				//过期时间, 时间戳这里转换用的是int32, 超过int最大长度的时候, 这个时间戳转Exp时间会挂, 取出来是个null, 
				//这种时候,可以使用jwtPayload["exp"]
				var expTime = jwtPayload.Exp ?? jwtPayload["exp"];

				//token还有半小时就过期的时候, 自动续期, 这个理论上不应该在这里做, token的签发和续期应该都由一个系统提供接口, 其他系统只负责校验就行, 这里比较特殊, 所以写了个续期
				var tokenTime = DateHelper.ToLocalDateTime(Convert.ToInt64(expTime));
				if (tokenTime > DateTime.Now)
				{
					if (tokenTime.Value < (DateTime.Now.AddMinutes(30)))
					{
						token = GenerateToken(userName);
						//校验成功
						ClaimsIdentity identity = new ClaimsIdentity(new List<Claim>()
							{
								new Claim(ClaimsName, userName),
								new Claim(ClaimTypes.Name, userName)
							}, Bearer.Trim());
						filterContext.HttpContext.User = new ClaimsPrincipal(identity);
					}
				}
				return;
			}
			catch (SecurityTokenExpiredException ex)
            {
                //表示过期
            }
            catch (Exception ex)
            {
                //系统异常
            }
			catch (SecurityTokenException se)
			{
			//token错误
				AuthFailResponse(filterContext);
			}
		}
		private void AuthFailResponse(AuthorizationContext filterContext)
		{
			filterContext.Result = new JsonResult
			{
				Data = new AuthResult
				{
					IsSuccess = true,
					AuthErrorCode = 401,
					ErrorMessage = "无权限访问!"
				},
				JsonRequestBehavior = JsonRequestBehavior.AllowGet
			};
		}
	}
}

总结

这里就不写登录的地方了, 理论上来说, token的续期不应该放在这里, 这边是有特殊业务要求, 所以写的, 正常情况下, 应该是要登录系统提供一个接口出来, 签发和续期都交给该系统, 甚至校验也可以都交给一个系统来做, 只不过这样对接口性能要求就比较高了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值