.net core Jwt token验证与jose token解析

1,894 阅读2分钟

一般项目中对接登录需要token验证用户信息,最近架构了一套后端基于.net core的系统框架,下面把过程中集成jwt遇到的问题分享给大家。 实现逻辑:

  1. 登录后利用jwt生成token包含用户基本信息返回给前端
  2. 前端拿到token后存储在前端,并且每次请求后端接口中传给后端
  3. 后端可以接收前端传入的token并使用jose进行解析 本篇主要讲解后端实现,前端token的存储与传递给后端方式,之后文章将会单独讲解

首先第一步,实现登录,并将登陆成功后的用户信息封装到token中,下面附代码:

        [AllowAnonymous]
        [HttpGet]
        public IActionResult Login(string userName, string pwd)
        {
            var pwdMd5 = Md5Helper.Md5(Md5Helper.Md5(pwd));
            if (!authService.AccountExist(userName, pwdMd5))
            {
                return BadRequest(new { message = "用户名或者密码错误" });
            }
            var claims = new[]
            {
                  new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                  new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds()}"),
                  new Claim(ClaimTypes.Name, userName),
                  new Claim("userId", "test"),
                  new Claim("name", userName)
                };
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
              issuer: Const.Domain,
              audience: Const.Domain,
              claims: claims,
              expires: DateTime.Now.AddMinutes(30),
              signingCredentials: creds);

            return Ok(new
            {
                token = new JwtSecurityTokenHandler().WriteToken(token)
            });
        }

登陆的实现不在此讲解,现在需要了解的是登录之后我们可以通过如下代码将部分登陆用户信息封装到token中

    var claims = new[]
            {
                  new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                  new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds()}"),
                  new Claim(ClaimTypes.Name, userName),
                  new Claim("userId", "test"),
                  new Claim("name", userName)
                };
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
              issuer: Const.Domain,
              audience: Const.Domain,
              claims: claims,
              expires: DateTime.Now.AddMinutes(30),
              signingCredentials: creds);

这里的 new Claim("userId", "test")与 new Claim("name", userName)是封装的我们系统登陆用户的信息,传送到前端,当接口调用时也可以根据token中携带的这部分信息识别当前用户。 另外 Const.SecurityKey是jwt加密的密钥, Const.Domain是站点地址 配置如下

    /// <summary>
    /// jwt配置类
    /// </summary>
    public static class Const
    {
        public const string SecurityKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB";
        /// <summary>
        /// 站点地址
        /// </summary>
        public const string Domain = "http://localhost:5000";

        public static string ValidAudience;
    }
}

封装完成后可以通过 new JwtSecurityTokenHandler().WriteToken(token)来利用封装的信息生成一个token,然后就把这个token返回给前端。

接下来前端在调用接口时会将上一步拿到的token 附加到请求头header 的 Authorization字段中, 后端在接收到接口请求时通过如下代码拿到请求中的token字符串

   var headers = _httpContextAccessor.HttpContext.Request.Headers["Authorization"];

接下来 可以通过jose来解析 拿到的token字符串 代码如下:

   public static Object decode2(string token) {
            var authInfo = Jose.JWT.Payload<UserInfo>(token.Replace("Bearer ", ""));
            return authInfo;
        }

UserInfo是自定义的用户类,里边字段跟前面登陆成功封装到token的字段名称一致,用于接收解析成功的用户信息。 这样便可以拿到登陆成功返回给前端,前端又传回来的token中的用户信息。

加班中时间紧迫,jwt的集成和jose的安装将在之后讲解。