• Token 认证(Asp.Net)


    场景:前后端分离,在客户端缓存用户的登录信息,减少与后端接口的交互次数,同时解决身份认证。

    Token 

    token 产生,用户登录成功,服务器端产生一个token并返给前端,前端将token保存在cookie或者localStorage里面,然后每次请求时都带上这个token,一般都带在请求头header里面

    token 内容,会话的标识比如UserID,Name,pwd加密,过期时间,签发时间,颁发人。

    token算法,base64(Header) + . + base64(payload) + . +  sign

    token 校验,当服务器端收到请求时,首先会校验token,校验有两种不同的方式

     一, token产生后保存在服务器端(redis或者其他比较速度快的缓存中) 。优点:可控性强,可以用这个来做单点登录,比如另一个地方登录,就remove掉之前的token。缺点:实现麻烦一点,而且要占服务器压力

    二, token产生后服务器端不保存,只负责校验。 优点:大大降低了服务器的压力,实现起来,也要相对简单一点。缺点:token一旦颁发,服务器端就不可控了,只能等它过期。(用的多)

    token    jwt算法 全名 Json Web Tokens 

     

    组成:

    • Header(头部,一般包含了token的签名方式)
    • Payload(负载,也就是具体的有效部分)
    • Signature(签名,将前两部分进行签名算法,防止客户端篡改)

    实现方式,将 header 部分和 payload 部分分别进行 base64 算法,然后用点号“.”隔开拼接,然后进行签名算法(MD5),然后在将三部分拼接(点号隔开)就得到了jwt 

    注意 ,jwt默认是采用base64编码的,也就是说 客户端也能解码得出具体内容的,所以除非特殊情况,重要敏感字段一定不能放在token中

    示例代码如下

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using System.Web;
    
    namespace NewWeb.Controllers
    {
        public class JWT
        {
    
            public static string SALT = "OXpcRP8jmCfMKumY";
    
    
            public static string Create(Dictionary<string, object> ExraPayload)
            {
                var Header = new Dictionary<string, object>();
                Header.Add("tp", "MD5");
    
                var Payload = new Dictionary<string, object>();
    
                // JWT 规定的7个官方属性,还可附加
                Payload.Add("iss", "signBy"); //颁发人
                Payload.Add("jti", Guid.NewGuid().ToString()); //jwt的id
                Payload.Add("exp", System.DateTime.Now.AddMinutes(20));//过期时间
                Payload.Add("nbf", System.DateTime.Now);//生效时间
                Payload.Add("iat", System.DateTime.Now);//签发时间
                Payload.Add("sub", "subject");//主题
                Payload.Add("aud", "audience");//受众
    
                foreach (var item in ExraPayload)
                {
                    if (Payload.ContainsKey(item.Key))
                    {
                        Console.WriteLine($"{item.Key}键值已被占用 不能使用 ");
                        throw new Exception($"{item.Key}键值已被占用 不能使用 ");
                    }
                    else {
                        Payload.Add(item.Key, item.Value);
                    }
                }
    
                // 将Header,Payload 通过Base64加密 通过. 拼接在一块
                string base64Header = Base64Url(Newtonsoft.Json.JsonConvert.SerializeObject(Header));
                string base64Payload = Base64Url(Newtonsoft.Json.JsonConvert.SerializeObject(Payload));
                string tmp = base64Header + "." + base64Payload;
    
                string sign = Md5(tmp + SALT);
    
                return base64Header + "." + base64Payload + "." + sign;
    
            }
    
    
            //校验是否合法,是否过期
            public static bool Check(string token)
            {
                string base64Header = token.Split('.')[0];
                string base64Payload = token.Split('.')[1];
                string sign = token.Split('.')[2];
                string tmp = base64Header + "." + base64Payload;
                var signCheck = Md5(base64Header + "." + base64Payload + SALT);
                if (signCheck != sign)
                {
                    return false;
                }
                var dic = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlDecode(base64Payload));
                if (Convert.ToDateTime(dic["exp"]) < System.DateTime.Now)
                {
                    //过期了
                    return false;
    
                }
                return true;
    
            }
            //校验是否合法,是否过期
            public static Dictionary<string, object> GetPayLoad(string token)
            {
    
                string base64Payload = token.Split('.')[1];
    
                var dic = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlDecode(base64Payload));
    
                return dic;
    
            }
    
            // Base64加密
            public static string Base64Url(string input)
            {
                //JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。
                //Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。
                string output = "";
                byte[] bytes = Encoding.UTF8.GetBytes(input);
                try
                {
                    output = Convert.ToBase64String(bytes).Replace('+', '-').Replace('/', '_').TrimEnd('=');
    
    
                }
                catch (Exception e)
                {
                    throw e;
                }
                return output;
            }
    
            // Base64 解密
            public static string Base64UrlDecode(string input)
            {
                string output = "";
    
                input = input.Replace('-', '+').Replace('_', '/');
                switch (input.Length % 4)
                {
                    case 2:
                        input += "==";
                        break;
                    case 3:
                        input += "=";
                        break;
                }
                byte[] bytes = Convert.FromBase64String(input);
                try
                {
                    output = Encoding.UTF8.GetString(bytes);
                }
                catch
                {
                    output = input;
                }
                return output;
            }
    
            //MD5 加密
            public static string Md5(string input, int bit = 16)
            {
    
                MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
                byte[] hashedDataBytes;
                hashedDataBytes = md5Hasher.ComputeHash(Encoding.GetEncoding("gb2312").GetBytes(input));
                StringBuilder tmp = new StringBuilder();
                foreach (byte i in hashedDataBytes)
                {
                    tmp.Append(i.ToString("x2"));
                }
                if (bit == 16)
                    return tmp.ToString().Substring(8, 16);
                else
                if (bit == 32) return tmp.ToString();//默认情况
                else return string.Empty;
    
            }
    
    
        }
    }
    View Code

    用postMan 调用接口进行传参调试

            public ActionResult Login(string name, string pwd)
            {
               // 检查是否存在当前用户
        
                //进行将信息传入字典创建token
                var dic =new Dictionary<string, object>();
                dic.Add(name,pwd);
    
                string token = JWT.Create(dic);
    
                //验证token是否正确是否过期
                var isChecked = JWT.Check(token);
    
                return Content("OK");
            }    

     参考资料:

    Aspnet Mvc 前后端分离项目手记(二)关于token认证--- https://www.cnblogs.com/jimsfriend/p/10548321.html

    JSON Web Token 入门教程 ---  http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

  • 相关阅读:
    Access中出现改变字段“自己主动编号”类型,不能再改回来!(已解决)
    移动闭塞
    信号系统基本设备介绍——应答器
    行车闭塞
    计轴
    联锁
    SqlServer 查看缓存 并合理设置最大内存
    SQL Server中bcp命令的用法以及数据批量导入导出
    5 个免费的受欢迎的 SQLite 管理工具
    Qt之操作数据库(SQLite)
  • 原文地址:https://www.cnblogs.com/zhangrh/p/14145213.html
Copyright © 2020-2023  润新知