JWT

发布时间 2023-08-27 20:35:22作者: IAMLCW

一.JWT的作用

 把JSON对象加密成为一个秘钥字符串,JWT的令牌由三个部分组成  JWT头,JWTToken   签名

 二.验证令牌的流程

首先由用户登录后将信息传到后台接口中生成JWT令牌,然后后台将JWT令牌返回给前端,前端可以保存到localStorage或sessionStoeage中

前端每次访问请求时会带着令牌传到后端,然后接口验证令牌的正确性,有效性,验证通过就会执行要执行的操作并返回响应的结果,否则就返回没有授权

三.如何配置JWT

首先安装Nuget包

然后在在appsettings.json配置

"Auth": {
    "SecretKey": "al45jgioasdjgoije8343050945049jg3409jgfoksdjfglaskdjfaiosdjfasdfsd", //私钥  长度 16位以上 自己随便输入 
    "Issuer": "www.aaabb.com",  //发行人
    "Audience": "www.ccdd.com"  //访问人
  }

然后创建一个TokenHelper类

public class TokenHelper
    {
        private readonly IConfiguration _configuration;
        private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler;
        public TokenHelper(IConfiguration configuration, JwtSecurityTokenHandler jwtSecurityTokenHandler)
        {
            _configuration = configuration;
            _jwtSecurityTokenHandler = jwtSecurityTokenHandler;
        }
        /// <summary>
        /// 创建加密JwtToken
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public string CreateJwtToken<T>(T user)
        {
            var signingAlogorithm = SecurityAlgorithms.HmacSha256;
            //CreateClaimList  将用户信息 加载到 载荷 当中
            var claimList = this.CreateClaimList(user);
            //Signature
            //取出私钥并以utf8编码字节输出
            var secretByte = Encoding.UTF8.GetBytes(_configuration["Auth:SecretKey"]);
            //使用非对称算法对私钥进行加密
            var signingKey = new SymmetricSecurityKey(secretByte);
            //使用HmacSha256来验证加密后的私钥生成数字签名
            var signingCredentials = new SigningCredentials(signingKey, signingAlogorithm);
            //生成Token
            var Token = new JwtSecurityToken(
          issuer: _configuration["Auth:Issuer"], //发布者
            audience: _configuration["Auth:Audience"], //接收者
            claims: claimList, //存放的用户信息
            notBefore: DateTime.UtcNow, //发布时间
            expires: DateTime.UtcNow.AddDays(1), //有效期设置为1天
            signingCredentials //数字签名
            );
            //生成字符串token
            var TokenStr = new JwtSecurityTokenHandler().WriteToken(Token);
            return TokenStr;
        }

        public T GetToken<T>(string Token)
        {
            Type t = typeof(T);
            //Activator.CreateInstance  根据 t(你传过来的泛型)   用反射的方式 new 当前对象  
            object objA = Activator.CreateInstance(t);
            var b = _jwtSecurityTokenHandler.ReadJwtToken(Token);
            foreach (var item in b.Claims)
            {
                PropertyInfo _Property = t.GetProperty(item.Type);
                if (_Property != null && _Property.CanRead)
                {
                    _Property.SetValue(objA, item.Value, null);
                }

            }
            return (T)objA;
        }
        /// <summary>
        /// 创建包含用户信息的CalimList
        /// </summary>
        /// <param name="authUser"></param>
        /// <returns></returns>
        private List<Claim> CreateClaimList<T>(T authUser)
        {
            var Class = typeof(T);
            //Claim 载荷的类 List
            List<Claim> claimList = new List<Claim>();
            //GetProperties 获取类型下所有的属性
            foreach (var item in Class.GetProperties())
            {
                //if (item.Name == "UPass")
                //{
                //    continue;
                //}
                claimList.Add(new Claim(item.Name, Convert.ToString(item.GetValue(authUser))));
            }
            return claimList;
        }
    }

然后在Program.cs中配置

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
    //返回的是 字符的数组
    var sercrtByte = Encoding.UTF8.GetBytes( builder.Configuration["Auth:SecretKey"]);
    //配置token验证
    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
    {
        ValidateIssuer = true,
        ValidIssuer = builder.Configuration["Auth:Issuer"],
        ValidateAudience = true,  
        ValidAudience = builder.Configuration["Auth:Audience"],
        //验证是否过期
        ValidateLifetime = true,
        //验证私钥
       IssuerSigningKey = new SymmetricSecurityKey(sercrtByte)

    };
});

在控制器将TokenHelper注入进去

public UserInfoController( TokenHelper tokenHelper)
        {
            _tokenHelper = tokenHelper;
        }

然后编写一个登录接口 在登录接口上一定要加上[AllowAnonymous] 这个是无需验证身份操作

/// <summary>
        /// 登录
        /// </summary>
        /// <param name="userInfoDto"></param>
        /// <returns></returns>
        [HttpPost]
        //允许所有人访问
        [AllowAnonymous]
        public IActionResult Login(UserInfoDto userInfoDto)
        { 
            ApiResult apiResult = new ApiResult();  
       
            var userInfo = _mapper.Map<UserInfoDto, UserInfo>(userInfoDto);

            var result = _userInfoRespority.Login(userInfo);
            if (result==null)
            {
                apiResult.Code = StausCode.ERROR;
                apiResult.Data = StatusMsg.LOGINERRORMSG;
                return Ok(apiResult);
            }
            //将实体转回dto
            UserDto? user = _mapper.Map<UserInfo, UserDto>(result);

            apiResult.Code = StausCode.SUCCESS;
            apiResult.Msg = StatusMsg.LOGINSUCCESSMSG;
            apiResult.Data = user;

            var token = _tokenHelper.CreateJwtToken(user);
            //将token 放到响应头当中
            Response.Headers["token"] = token;
            Response.Headers["Access-Control-Expose-Headers"] = "token";

            return  Ok(apiResult);
        }

这样一个JWT就写好了