token
token
1.简介
一般是用户登录成功,服务器会颁发一个token并返回给前端。前端将token保持在cookie或者localStorage里面,然后每次请求是都会带上这个token,一般都带在请求头里面。
2.token的内容
一般token里面必须有的是:
(1)会话用户标识:比如userid。
(2)token的过期时间,如果想更完整一点,可以加上token的颁发者,签名等等。
3.token的生成算法
一般是由服务器端将token的主要内容,过期时间等等做非对称加密,然后进行签证算法(防止客户端更改),具体看后面Jwt
4.token校正
当服务器收到请求时,首先校正token,校正有二种不同的方式。
(1)token生成后保存在服务器端(redis或者其他速度比较快的缓存中)。
优点:可控性强,可以用这个用来做单点登录,比如用另一个地方登录,就remove掉之前的token。
缺点:实现麻烦一点,并且占服务器内存。
(2)token生成后服务器不负责保存只负责校验。
优点:大大的减轻了服务器的压力。实现起来相对简单些。
缺点:一旦颁发就不可控,只能让它自动过期。
Jwt
1.Jwt全面Json Web Token,算是一种token规范。
2.组成有三部分
(1)Header:头部,一般包括token的签名方式。
(2)PayLoad:负载,也就是具体有效部分。
(3)Signature:签名,将前两部分进行签名算法,防止被篡改。
实现方式,将Header部分和payLoad部分分别进行base64算法,然后用点号“.”隔开拼接,然后进行签名算法,
然后在将三部分拼接(点号隔开)就得到Jwt
注意:jwt默认是采用base64编码的,也就是说客户端也能解码得出具体内容,所以除非特殊情况,重要敏感字段一等不能放在token中。
下面是具体实现:
创建个Jwt类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | public class Jwt { public static string SALT = "OXpcRP8jmCfMKumY" ; /// <summary> /// /// </summary> /// <param name="ExraPayload">额外的信息</param> /// <returns></returns> public static string Create(Dictionary< string , object > ExraPayload) { var Header = new Dictionary< string , string >(); 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)) { throw new Exception($ "{item.Key}键值已被占用 不能使用 " ); } else { Payload.Add(item.Key, item.Value); } } 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; } 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; } 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; } 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; } } |
使用方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public ActionResult LoginTokenCode( string username, string userpwd) { //todo 验证用户名密码正确 if (username!= "sa" && userpwd!= "123" ) { return View( "LoginToken" ); } //在token中加入用户id,创建token var dic = new Dictionary< string , object >(); dic.Add( "Id" , "qwe" ); string token = Jwt.Create(dic); //验证token是否正确是否过期 var isChecked = Jwt.Check(token); return Content( "成功!!" ); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具