欢迎光临
个人技术文档整理

NET Core认证授权之JWT-生成和解码令牌(一)

介绍

JWT全称是JSON web token,它是使用JSON格式来保存令牌信息的。JWT机制不是把用户的登录信息保存在服务器端,而是把登录信息(也叫作令牌)保存在客户端。为了防止客户端的数据造假,保存在客户端的令牌经过了签名处理,而签名的密钥只有服务器端才知道,每次服务器端收到客户端提交的令牌的时候都要检查一下签名,如果发现数据被篡改,则拒绝接收客户端提交的令牌

  • 头部(header)中保存的是加密算法的说明。
  • 负载(payload)中保存的是用户的ID、用户名、角色等信息。
  • 签名(signature)是根据头部和负载一起算出来的值。

JWT实现登录的流程如下。

  1. 客户端向服务器端发送用户名、密码等请求登录。
  2. 服务器端校验用户名、密码,如果校验成功,则从数据库中取出这个用户的ID、角色等用户相关信息。
  3. 服务器端采用只有服务器端才知道的密钥来对用户信息的JSON字符串进行签名,形成签名数据。
  4. 服务器端把用户信息的JSON字符串和签名拼接到一起形成JWT,然后发送给客户端。
  5. 客户端保存服务器端返回的JWT,并且在客户端每次向服务器端发送请求的时候都带上这个JWT。
  6. 每次服务器端收到浏览器请求中携带的JWT后,服务器端用密钥对JWT的签名进行校验,如果校验成功,服务器端则从JWT中的JSON字符串中读取出用户的信息。

这样服务器端就知道这个请求对应的用户了,也就实现了登录的功能。

由此可以看出,在JWT机制下,登录用户的信息保存在客户端,服务器端不需要保存数据,这样我们的程序就天然地适合分布式的集群环境,而且服务器端从客户端请求中就可以获取当前登录用户的信息,不需要再去状态服务器中获取,因此程序的运行效率更高。虽然用户信息保存在客户端,但是由于有签名的存在,客户端无法篡改这些用户信息,因此可以保证客户端提交的JWT的可信度。

安装NuGet包

Install-Package Microsoft.IdentityModel.Tokens
Install-Package System.IdentityModel.Tokens.Jwt

Jwt辅助类(生成令牌,解码令牌) 

    public class JwtHelper
    {
        private string _SecurityKey;//秘钥 注意:密钥长度需要大于16位
        private string _Issuer;//jwt签发者
        private string _Audience;//接收jwt的一方 
        private int _Expires;//jwt的过期时间,这个过期时间必须要大于签发时间
        public JwtHelper()
        {
            _SecurityKey = "1234567890123456";
            _Expires = 3600;

        }
        /// <summary>
        /// 根据账号密码生成 Token
        /// </summary>
        public string GetToken(string loginName, string loginPassword)
        {
            #region 有效载荷, 可以自己写,爱写多少写多少;尽量避免敏感信息

            var cls = new[]
            {
                new Claim("loginName",loginName),
                new Claim("loginPassword",loginPassword),
            };
            #endregion

            //加密  
            //依赖Nuget:Microsoft.IdentityModel.Tokens
            SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_SecurityKey));
            //签名
            SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            //依赖Nuget:System.IdentityModel.Tokens.Jwt 
            var jwtSecurityToken = new JwtSecurityToken(
                   issuer: _Issuer,//jwt签发者
                   audience: _Audience,//接收jwt的一方 
                   notBefore: DateTime.Now,//定义在什么时间之前,该jwt都是不可用的
                   expires: DateTime.Now.AddSeconds(_Expires),//jwt的过期时间,这个过期时间必须要大于签发时间
                   claims: cls,
                   signingCredentials: creds
                );

            var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);

            return token;
        }

         /// <summary>
    /// 对jwt字符串 解码
    /// </summary> 
    public Dictionary<string, string> DecodeJwt(string jwtStr)
    {
        Dictionary<string, string> dic = new Dictionary<string, string>();
        var jwtHandler = new JwtSecurityTokenHandler();
        // token校验
        if (!string.IsNullOrEmpty(jwtStr) && jwtHandler.CanReadToken(jwtStr))
        {
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);

            var claims = jwtToken.Claims;

            foreach (var claim in claims)
            {
                dic.Add(claim.Type, claim.Value);
            }
        }
        return dic;
    }
    }

Program.cs

  
JwtHelper jwtHelper = new JwtHelper();

//生成JWT令牌
var jwtToken = jwtHelper.GetToken("demo", "123456");
Console.WriteLine(jwtToken);

//解码JWT令牌
var dic = jwtHelper.DecodeJwt(jwtToken);

Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(dic));

 

赞(2)