概述
1、自动登陆实现思路。
2、vuex + cookie 多标签页状态保持。
自动登陆的需求:
1、登陆时勾选自动登陆,退出登陆或登陆到期后再次登陆后自动填写表单(记住密码)或访问登陆页自动登陆。
2、安全性需求,cookie 的有效性判断应该放到服务端。
实现细节
1、后台:一个静态的登陆管理类 负责管理登陆用户,这里设计了两个 cookie 一个用来保存登陆信息、一个用来保存自动登陆信息。
登陆cookie 的有效时间是 30 分钟,自动登陆cookie 的有效时间是 3 天,分别保存了用户名、编码、密码;用户名、编码、密码、时间戳。
后台包含,RSA加密算法、cookie 管理、登陆相关业务(登入、登出、过滤器)。不干兴趣跳过,看前端代码。
1 /// <summary> 2 /// 登录用户管理 3 /// </summary> 4 public static class LoginUserManager 5 { 6 public const string DBENLOGININ = "DBEN.OP.LOGININ"; 7 public const string DBENAUTOLOGIN = "DBEN.OP.AUTOLOGIN"; 8 public const string DBENUSERCODE = "DBEN.OP.USERCODE"; 9 public const string DBENUSERNAME = "DBEN.OP.USERNAME"; 10 public const string DBENUSERPWD = "DBEN.OP.USERPASSWORD"; 11 12 /// <summary> 13 /// RSA 加解密实例 14 /// </summary> 15 public static RSAApply RSAApply 16 { 17 get 18 { 19 return new RSAApply( 20 ConfigHelper.GetAppSetting("DBEN.StaticRSAPublicKey", @"MIGfM 21 A0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBRxFQos7Nc77goLB6cz2SM6Ae7OuuOTkycG2eyP 22 Lds7+hE8s6bqJMfdY6EOlPjGraATXSCsrPnowWeq2p59xyejJLlCfX3dE+Br5FuUG+MwK7K6i 23 HQ2lJLZlvnnmDqjmHO2+k14VOFwlXNOKkciWVsjT/mr4Xj4olG2gjOhWvqQIDAQAB"), 24 ConfigHelper.GetAppSetting("DBEN.StaticRSAPrivateKey", @"MIIC 25 dwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMFHEVCizs1zvuCgsHpzPZIzoB7s6 26 645OTJwbZ7I8t2zv6ETyzpuokx91joQ6U+MatoBNdIKys+ejBZ6rann3HJ6MkuUJ9fd0T4Gvk 27 W5Qb4zArsrqIdDaUktmW+eeYOqOYc7b6TXhU4XCVc04qRyJZWyNP+avhePiiUbaCM6Fa+pAgM 28 BAAECgYAePxDmnZPfcw2b+YmkoAQyrQGR1WHMkgfxbMa64pefOlHy0zYqnsWnUsoDrEHWwRK3 29 qxjRFf9HHnity+UBgddtjRrSW9ly+5zSvTTVb3wHfSqV/xJsakZ3M8MjVLCQXZarXTbRlYBnx 30 eFLcvvfouDHbefK6cqIpEk1uWllq7eNQQJBAOpWf2gsvGnFTU0vrx77Ed1QHH0C4ldss63N91 31 /YbrmNl9jQNcWD2DG3tw3ToSM8JIAb1Rdw9/kwpoqW9qp0mI8CQQDTJOWQum/+oovU7MZrgzR 32 K3N/wVXt4GIDgL4k48NSvzA+jRGf5MdphsqQKHuws9F4O+P7w/mK2QOHx4ys8OqBHAkEAnj6L 33 Cu4qzcJO0TDCMUmaZrkSg9jOv/rH2zabNj4Rh3v2bpMrvJWsCObm1o9y4Thb7abd31aKHdycm 34 joXmEPkQQJAW62hn/3TsxSQ8pr8bKJDil3tPkVfnv3Et5LsWjT3pH1OLO3+10y2LcWLRHm4wq 35 w4SvgCelF6OvhhIs4ob7Zk8QJBAIXEwsLcy9xZaRt85dIWuJFfbuAmCXiNWSJEhIFYPkLUvi2 36 QHZTdLHpSbi5oCPIVKw4CDTAP4b+JfGrrFaZjWNc=")); 37 } 38 } 39 40 /// <summary> 41 /// 已登录 42 /// </summary> 43 /// <param name="userCode"></param> 44 public static void SetLoginIn(string userCode, string userName, string userPassword) 45 { 46 var dic = new Dictionary<string, string> 47 { 48 { DBENUSERCODE, userCode }, 49 { DBENUSERNAME, userName }, 50 { DBENUSERPWD, userPassword } 51 }; 52 CookieManager.SetCookie(DBENLOGININ, RSAApply.GetCiphertext(dic, false)); 53 } 54 55 public static void SetLoginOut() 56 { 57 CookieManager.RemoveCookie(DBENLOGININ); 58 } 59 60 /// <summary> 61 /// 自动登录 62 /// </summary> 63 /// <param name="userCode"></param> 64 public static void SetAutoLogin(string userCode, string userName, string userPassword) 65 { 66 if (CookieManager.GetCookie(DBENAUTOLOGIN) == null) 67 { 68 //首次勾选自动登录,创建自动登录的cookie。 69 var dic = new Dictionary<string, string> 70 { 71 { DBENUSERCODE, userCode }, 72 { DBENUSERNAME, userName }, 73 { DBENUSERPWD, userPassword } 74 }; 75 CookieManager.SetCookie(new HttpCookie(DBENAUTOLOGIN, RSAApply.GetCiphertext(dic, true)) { Expires = DateTime.Now.AddDays(RSAApply.ValidityDays) }); 76 } 77 //通过自动登录也要设置已登录的 cookie 78 SetLoginIn(userCode, userName, userPassword); 79 } 80 81 /// <summary> 82 /// 检查客户端状态 83 /// </summary> 84 /// <returns></returns> 85 public static bool CheckClientStatus(out Dictionary<string, string> user) 86 { 87 /**** 88 * 如果存在 已登录 cookie 且译文有效,用户未被禁用,则返回true 89 * 否则检验 自动登录 cookie。 90 * 自动登录 cookie 存在且译文有效,自动登录后返回 true。 91 * */ 92 93 var cookie = CookieManager.GetCookie(DBENLOGININ); 94 if (cookie != null) 95 { 96 return CheckCiphertext(cookie.Value, out user); 97 } 98 else 99 { 100 // 如果不是已登录,检查是否存在自动登录 cookie 101 cookie = CookieManager.GetCookie(DBENAUTOLOGIN); 102 if (cookie != null) 103 { 104 if (CheckCiphertext(cookie.Value, out user)) 105 { 106 //将此用户设置为已登录 107 SetLoginIn(user[DBENUSERCODE], user[DBENUSERNAME], user[DBENUSERPWD]); 108 return true; 109 } 110 } 111 user = null; 112 return false; 113 } 114 } 115 116 /// <summary> 117 /// 获取客户端用户信息 118 /// </summary> 119 /// <returns>返回一个从 cookie 创建的新实例</returns> 120 public static OPUserEntity GetClientUserInfo() 121 { 122 OPUserEntity res = null; 123 if (CheckClientStatus(out Dictionary<string, string> user)) 124 { 125 res = new OPUserEntity 126 { 127 Code = user[DBENUSERCODE], 128 UserName = user[DBENUSERNAME], 129 Password = user[DBENUSERPWD] 130 }; 131 } 132 return res; 133 } 134 135 /// <summary> 136 /// 校验密文有效性,包括密文能否解密、账户有效性。 137 /// </summary> 138 /// <param name="ciphertext">密文</param> 139 /// <param name="user">如果返回值为方式则返回一个空实例</param> 140 /// <returns></returns> 141 private static bool CheckCiphertext(string ciphertext, out Dictionary<string, string> user) 142 { 143 user = new Dictionary<string, string>(); 144 var repo = RF.ResolveInstance<OPUserEntityRepository>(); 145 if (RSAApply.TryGetSource(ciphertext, ref user)) 146 { 147 if (user.TryGetValue(DBENUSERCODE, out string userCode)) 148 { 149 if (user.TryGetValue(DBENUSERPWD, out string userPwd)) 150 { 151 if (user.TryGetValue(DBENUSERNAME, out string userName)) 152 { 153 var count = repo.CountBy(new CommonQueryCriteria 154 { 155 { OPUserEntity.UserNameProperty,userName }, 156 { OPUserEntity.CodeProperty,userCode }, 157 { OPUserEntity.PasswordProperty,userPwd }, 158 { OPUserEntity.EnabledProperty,true }, 159 }); 160 return count > 0; 161 } 162 } 163 } 164 } 165 166 return false; 167 } 168 169 170 }
- 组合类 RSA 加密实例
1 /// <summary> 2 /// RSA 加密应用实例 3 /// </summary> 4 public class RSAApply 5 { 6 readonly string xmlPublicKey; 7 readonly string xmlPrivateKey; 8 readonly RSACryption rSACryption; 9 const string TIMESTAMPKEY = "RSAApply_timeStamp"; 10 11 /// <summary> 12 /// 追加时间戳情况下的有效天数 13 /// </summary> 14 public int ValidityDays { get; internal set; } 15 16 public RSAApply(string base64PublicKey, string base64PrivateKey) 17 { 18 this.xmlPublicKey = RSAKeyConvert.RSAPublicKeyBase64ToXml(base64PublicKey); 19 this.xmlPrivateKey = RSAKeyConvert.RSAPrivateKeyBase64ToXml(base64PrivateKey); 20 rSACryption = new RSACryption(); 21 } 22 23 /// <summary> 24 /// 获取密文 25 /// </summary> 26 /// <returns></returns> 27 public string GetCiphertext(Dictionary<string, string> source, bool timestamp = false) 28 { 29 if (timestamp) 30 { 31 source.Add(TIMESTAMPKEY, TimeHelper.GetTStamp()); 32 } 33 var sourceStr = JsonConvert.SerializeObject(source, Formatting.Indented); 34 var ciphertext = rSACryption.RSAEncrypt(xmlPublicKey, sourceStr); 35 return ciphertext; 36 } 37 38 /// <summary> 39 /// 获取明文 40 /// </summary> 41 /// <returns></returns> 42 public bool TryGetSource(string cipertext, ref Dictionary<string, string> source) 43 { 44 var sourceStr = rSACryption.RSADecrypt(xmlPrivateKey, cipertext); 45 source = JsonConvert.DeserializeObject<Dictionary<string, string>>(sourceStr); 46 47 if (source.TryGetValue(TIMESTAMPKEY, out string timeStemp)) 48 { 49 if ((DateTime.Now - long.Parse(timeStemp).ToTimeStamp()).TotalDays > ValidityDays) 50 { 51 return false; 52 } 53 source.Remove(TIMESTAMPKEY); 54 } 55 return true; 56 } 57 }
- RSA 加密帮助类
1 public class RSACryption 2 { 3 4 #region 私有属性 5 6 private Encoding rsaEncoding 7 { 8 get 9 { 10 return Encoding.Unicode; 11 } 12 } 13 14 private Encoding hashEncoding 15 { 16 get 17 { 18 return Encoding.UTF8; 19 } 20 } 21 22 #endregion 23 24 #region RSA 加密解密 25 26 #region RSA 的密钥产生 27 28 /// <summary> 29 /// RSA产生密钥 30 /// </summary> 31 /// <param name="xmlPrivateKey">私钥</param> 32 /// <param name="xmlPublicKey">公钥</param> 33 /// <returns></returns> 34 public bool RSACreateKey(out string xmlPrivateKey, out string xmlPublicKey) 35 { 36 try 37 { 38 var rsaProvider = new RSACryptoServiceProvider(1024); 39 xmlPrivateKey = rsaProvider.ToXmlString(true); 40 xmlPublicKey = rsaProvider.ToXmlString(false); 41 return true; 42 } 43 catch (Exception) 44 { 45 xmlPrivateKey = string.Empty; 46 xmlPublicKey = string.Empty; 47 return false; 48 } 49 } 50 51 #endregion 52 53 #region RSA加密函数 54 55 /// <summary> 56 /// RSA 加密 57 /// 首先对原始字符串做MD5哈希,然后再对哈希值加密。 58 /// </summary> 59 /// <param name="publicKeyBase64String"></param> 60 /// <param name="source"></param> 61 /// <returns></returns> 62 public string RSAEncryption(string publicKeyBase64String, string source) 63 { 64 string hashValue = string.Empty; 65 this.ComputeMD5Hash(source, ref hashValue); 66 var pck = RSAKeyConvert.RSAPublicKeyBase64ToXml(publicKeyBase64String); 67 var ciphertext = this.RSAEncrypt(pck, hashValue); 68 return ciphertext; 69 } 70 71 /// <summary> 72 /// RSA的加密函数 73 /// </summary> 74 /// <param name="xmlPublicKey">公钥</param> 75 /// <param name="srouce">待加密文本</param> 76 /// <returns></returns> 77 public string RSAEncrypt(string xmlPublicKey, string srouce) 78 { 79 byte[] plainTextBytes = this.rsaEncoding.GetBytes(srouce); 80 return this.RSAEncrypt(xmlPublicKey, plainTextBytes); 81 } 82 83 /// <summary> 84 /// RSA的加密函数 85 /// </summary> 86 /// <param name="xmlPublicKey">公钥</param> 87 /// <param name="sourceBytes">加密后的字节数组</param> 88 /// <returns></returns> 89 public string RSAEncrypt(string xmlPublicKey, byte[] sourceBytes) 90 { 91 try 92 { 93 byte[] cypherTextBytes; 94 string res = string.Empty; 95 var rsaProvider = new RSACryptoServiceProvider(); 96 rsaProvider.FromXmlString(xmlPublicKey); 97 cypherTextBytes = rsaProvider.Encrypt(sourceBytes, false); 98 res = Convert.ToBase64String(cypherTextBytes); 99 return res; 100 } 101 catch (Exception) { return string.Empty; } 102 } 103 104 #endregion 105 106 #region RSA的解密函数 107 108 /// <summary> 109 /// RSA 解密 110 /// 解密失败则返回空字符串 111 /// </summary> 112 /// <param name="xmlPrivateKey">XML格式的私钥</param> 113 /// <param name="encryptString">加密后的字符串</param> 114 /// <returns>解密后的字符串</returns> 115 public string RSADecrypt(string xmlPrivateKey, string encryptString) 116 { 117 byte[] encryptBytes = Convert.FromBase64String(encryptString); 118 return this.RSADecrypt(xmlPrivateKey, encryptBytes); 119 } 120 121 /// <summary> 122 /// RSA 解密 123 /// 解密失败则返回空字符串 124 /// </summary> 125 /// <param name="xmlPrivateKey">XML格式的私钥</param> 126 /// <param name="encryptBytes">加密后的字节数组</param> 127 /// <returns>解密后的字符串</returns> 128 public string RSADecrypt(string xmlPrivateKey, byte[] encryptBytes) 129 { 130 try 131 { 132 var rsaProvider = new RSACryptoServiceProvider(); 133 rsaProvider.FromXmlString(xmlPrivateKey); 134 byte[] dypherTextBytes = rsaProvider.Decrypt(encryptBytes, false); 135 string res = this.rsaEncoding.GetString(dypherTextBytes); 136 return res; 137 } 138 catch (Exception) { return string.Empty; } 139 } 140 141 #endregion 142 143 #endregion 144 145 #region RSA数字签名 146 147 #region MD5 Hash 148 149 /// <summary> 150 /// 计算Hash(MD5) 151 /// </summary> 152 /// <param name="sourceString">原始字符串</param> 153 /// <param name="hashString">Hash值</param> 154 /// <returns>是否成功</returns> 155 public bool ComputeMD5Hash(string sourceString, ref string hashString) 156 { 157 byte[] hashBytes = new byte[0]; 158 var res = this.ComputeMD5Hash(sourceString, ref hashBytes); 159 hashString = Convert.ToBase64String(hashBytes); 160 return res; 161 } 162 163 /// <summary> 164 /// 计算Hash(MD5) 165 /// </summary> 166 /// <param name="srourceString">原始字符串</param> 167 /// <param name="hashBytes">Hash值</param> 168 /// <returns>是否成功</returns> 169 public bool ComputeMD5Hash(string srourceString, ref byte[] hashBytes) 170 { 171 try 172 { 173 var md5Provider = HashAlgorithm.Create("MD5"); 174 byte[] buffer = this.hashEncoding.GetBytes(srourceString); 175 hashBytes = md5Provider.ComputeHash(buffer); 176 return true; 177 } 178 catch (Exception) { return false; } 179 } 180 181 #endregion 182 183 #region RSA 创建签名 184 185 /// <summary> 186 /// 生成RSA签名 187 /// 签名算法:MD5 188 /// </summary> 189 /// <param name="xmlPrivateKey">XML私钥</param> 190 /// <param name="hashString">待签名Hash值</param> 191 /// <param name="signatureString">签名的值</param> 192 /// <returns>是否成功</returns> 193 public bool CreateSignature(string xmlPrivateKey, string hashString, ref string signatureString) 194 { 195 byte[] hashBytes = Convert.FromBase64String(hashString); 196 var signatureBytes = new byte[0]; 197 var res = this.CreateSignature(xmlPrivateKey, hashBytes, ref signatureBytes); 198 signatureString = Convert.ToBase64String(signatureBytes); 199 return res; 200 } 201 202 /// <summary> 203 /// 生成RSA签名 204 /// 签名算法:MD5 205 /// </summary> 206 /// <param name="xmlPrivateKey">XML私钥</param> 207 /// <param name="hashBytes">待签名Hash值</param> 208 /// <param name="signatureString">签名的值</param> 209 /// <returns>是否成功</returns> 210 public bool CreateSignature(string xmlPrivateKey, byte[] hashBytes, ref string signatureString) 211 { 212 var signatureBytes = new byte[0]; 213 var res = this.CreateSignature(xmlPrivateKey, hashBytes, ref signatureBytes); 214 signatureString = Convert.ToBase64String(signatureBytes); 215 return res; 216 } 217 218 /// <summary> 219 /// 生成RSA签名 220 /// 签名算法:MD5 221 /// </summary> 222 /// <param name="xmlPrivateKey">XML私钥</param> 223 /// <param name="hashString">待签名Hash值</param> 224 /// <param name="signatureBytes">签名的值</param> 225 /// <returns>是否成功</returns> 226 public bool CreateSignature(string xmlPrivateKey, string hashString, ref byte[] signatureBytes) 227 { 228 byte[] hashBytes = Convert.FromBase64String(hashString); 229 return this.CreateSignature(xmlPrivateKey, hashBytes, ref signatureBytes); 230 } 231 232 /// <summary> 233 /// 生成RSA签名 234 /// 签名算法:MD5 235 /// </summary> 236 /// <param name="xmlPrivateKey">XML私钥</param> 237 /// <param name="hashBytes">待验证的Hash值</param> 238 /// <param name="signatureBytes">签名的值</param> 239 /// <returns>是否成功</returns> 240 public bool CreateSignature(string xmlPrivateKey, byte[] hashBytes, ref byte[] signatureBytes) 241 { 242 try 243 { 244 var rsaProvider = new RSACryptoServiceProvider(); 245 246 rsaProvider.FromXmlString(xmlPrivateKey); 247 var rsaFormatter = new RSAPKCS1SignatureFormatter(rsaProvider); 248 //设置算法 249 rsaFormatter.SetHashAlgorithm("MD5"); 250 //执行签名 251 signatureBytes = rsaFormatter.CreateSignature(hashBytes); 252 return true; 253 } 254 catch (Exception) { return false; } 255 } 256 257 #endregion 258 259 #region RSA 验证签名 260 261 /// <summary> 262 /// 验证RSA签名 263 /// </summary> 264 /// <param name="xmlPublicKey">XML公钥</param> 265 /// <param name="hashString">待验证的Hash值</param> 266 /// <param name="signatureString">签名的值</param> 267 /// <returns></returns> 268 public bool VerifySignature(string xmlPublicKey, string hashString, string signatureString) 269 { 270 byte[] signatureBytes = Convert.FromBase64String(signatureString); 271 byte[] hashBytes = Convert.FromBase64String(hashString); 272 return this.VerifySignature(xmlPublicKey, hashBytes, signatureBytes); 273 } 274 275 /// <summary> 276 /// 验证RSA签名 277 /// </summary> 278 /// <param name="xmlPublicKey">XML公钥</param> 279 /// <param name="hashBytes">待验证的Hash值</param> 280 /// <param name="signatureString">签名的值</param> 281 /// <returns></returns> 282 public bool VerifySignature(string xmlPublicKey, byte[] hashBytes, string signatureString) 283 { 284 byte[] signatureBytes = Convert.FromBase64String(signatureString); 285 return this.VerifySignature(xmlPublicKey, hashBytes, signatureBytes); 286 } 287 288 /// <summary> 289 /// 验证RSA签名 290 /// </summary> 291 /// <param name="xmlPublicKey">XML公钥</param> 292 /// <param name="hashString">待验证的Hash值</param> 293 /// <param name="signatureBytes">签名的值</param> 294 /// <returns>验签结果</returns> 295 public bool VerifySignature(string xmlPublicKey, string hashString, byte[] signatureBytes) 296 { 297 byte[] hashBytes = Convert.FromBase64String(hashString); 298 return this.VerifySignature(xmlPublicKey, hashBytes, signatureBytes); 299 } 300 301 /// <summary> 302 /// 验证RSA签名 303 /// </summary> 304 /// <param name="xmlPublicKey">XML公钥</param> 305 /// <param name="hashBytes">待验证的Hash值</param> 306 /// <param name="signatureBytes">签名的值</param> 307 /// <returns>验签结果</returns> 308 public bool VerifySignature(string xmlPublicKey, byte[] hashBytes, byte[] signatureBytes) 309 { 310 try 311 { 312 var rsaProvider = new RSACryptoServiceProvider(); 313 rsaProvider.FromXmlString(xmlPublicKey); 314 var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsaProvider); 315 //指定解密的时候HASH算法为MD5 316 rsaDeformatter.SetHashAlgorithm("MD5"); 317 if (rsaDeformatter.VerifySignature(hashBytes, signatureBytes)) 318 { 319 return true; 320 } 321 else 322 { 323 return false; 324 } 325 } 326 catch (Exception) { return false; } 327 } 328 329 #endregion 330 331 #endregion 332 333 }
- RSA 密钥格式转换类
1 /// <summary> 2 /// RSA密钥格式转换 3 /// </summary> 4 public class RSAKeyConvert 5 { 6 7 #region 私钥转换 8 9 /// <summary> 10 /// RSA私钥 Base64 To XML 11 /// </summary> 12 /// <param name="privateKey">Base64格式的私钥</param> 13 /// <returns></returns> 14 public static string RSAPrivateKeyBase64ToXml(string privateKey) 15 { 16 var privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey)); 17 return 18 string.Format( 19 "<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>", 20 Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()), 21 Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()), 22 Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()), 23 Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()), 24 Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()), 25 Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()), 26 Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()), 27 Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned())); 28 } 29 30 /// <summary> 31 /// RSA私钥 XML To Base64 32 /// </summary> 33 /// <param name="privateKey">XML格式的私钥</param> 34 /// <returns></returns> 35 public static string RSAPrivateKeyXmlToBase64(string privateKey) 36 { 37 XmlDocument doc = new XmlDocument(); 38 doc.LoadXml(privateKey); 39 BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText)); 40 BigInteger exp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText)); 41 BigInteger d = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[0].InnerText)); 42 BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[0].InnerText)); 43 BigInteger q = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[0].InnerText)); 44 BigInteger dp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[0].InnerText)); 45 BigInteger dq = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[0].InnerText)); 46 BigInteger qinv = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[0].InnerText)); 47 RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv); 48 PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam); 49 byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded(); 50 return Convert.ToBase64String(serializedPrivateBytes); 51 } 52 53 #endregion 54 55 #region 公钥转换 56 57 /// <summary> 58 /// RSA公钥 Base64 To XML 59 /// </summary> 60 /// <param name="publicKey">Base64格式的公钥</param> 61 /// <returns></returns> 62 public static string RSAPublicKeyBase64ToXml(string publicKey) 63 { 64 RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey)); 65 return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>", 66 Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()), 67 Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned())); 68 } 69 70 /// <summary> 71 /// RSA公钥 XML To Base64 72 /// </summary> 73 /// <param name="publicKey">XML格式的公钥</param> 74 /// <returns></returns> 75 public static string RSAPublicKeyXmlToBase64(string publicKey) 76 { 77 XmlDocument doc = new XmlDocument(); 78 doc.LoadXml(publicKey); 79 BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText)); 80 BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText)); 81 RsaKeyParameters pub = new RsaKeyParameters(false, m, p); 82 SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub); 83 byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded(); 84 return Convert.ToBase64String(serializedPublicBytes); 85 } 86 87 #endregion 88 89 }
- mvc 过滤器
1 public class APIAuthedAttribute : ActionFilterAttribute 2 { 3 public override void OnActionExecuting(HttpActionContext context) 4 { 5 base.OnActionExecuting(context); 6 if (!LoginUserManager.CheckClientStatus(out Dictionary<string, string> user)) 7 { 8 context.Response = context.Request.CreateResponse<Result>( 9 HttpStatusCode.OK, 10 new 11 { 12 StatusCode = 1000, 13 Message = "请先登录", 14 Success = false 15 }); 16 } 17 } 18 }
2、前台
- 添加 vuex 目录结构。
- 安装 vuex 、js-cookie
npm install --save vuex js-cookie
1 // initial state 2 // shape: [{ id, quantity }] 3 import {AuthUser} from "../../api/api"; 4 import * as Cookies from "js-cookie" 5 6 const state = { 7 loginState: { 8 loginIn: false, 9 user: { 10 userName: "" 11 } 12 } 13 } 14 15 // getters 16 const getters = { 17 userName: (state, getters, rootState) => { 18 if (state.loginState.loginIn) { 19 return state.loginState.user.userName 20 } 21 }, 22 offLine: (state, getters, rootState) => { 23 return !state.loginState.loginIn; 24 } 25 } 26 27 //actions 28 const actions = { 29 //从服务器端校验本地登录 Cookie 有效性 30 authUser({state, commit}) { 31 return AuthUser().then(res => { 32 debugger; 33 if (res.Success) { 34 commit('loginIn', {userName: res.Data.UserName}); 35 return true; 36 } else { 37 commit('loginOut'); 38 return false; 39 } 40 }); 41 } 42 } 43 44 45 // mutations 46 const mutations = { 47 //登入状态 48 loginIn(state, user) { 49 state.loginState.loginIn = true; 50 state.loginState.user = user; 51 debugger; 52 Cookies.set('loginState', state.loginState, {expires: 1}); 53 }, 54 //登出状态 55 loginOut(state) { 56 state.loginState.loginIn = false; 57 state.loginState.user = {}; 58 Cookies.remove('loginState'); 59 }, 60 syncLoginState(state) { 61 debugger; 62 let cookieState = Cookies.getJSON('loginState'); 63 if (cookieState) { 64 state.loginState = cookieState; 65 } 66 } 67 } 68 69 export default { 70 namespaced: true, 71 state, 72 getters, 73 actions, 74 mutations 75 }
1 import Vue from 'vue' 2 import Vuex from 'vuex' 3 import user from './modules/user' 4 5 Vue.use(Vuex) 6 7 const debug = process.env.NODE_ENV !== 'production' 8 9 export default new Vuex.Store({ 10 modules: { 11 user 12 }, 13 strict: debug, 14 plugins: [] 15 })
- 在入口函数添加用户登陆状态判断 比如main.js
router.beforeEach((to, from, next) => { debugger; //离线用户跳转到首页 if (to.path != '/') { router.app.$store.commit('user/syncLoginState'); if (router.app.$store.getters['user/offLine']) { //离线用户鉴权,如果成功会自动登录 router.app.$store.dispatch('user/authUser').then((res) => { if (res) { next(); }else { next({path: '/'}); } }); return; } } next(); });
就这些了,登入,登出等操作就不贴代码了。
总结一下用到的点:
1、vuex 的存储源是一个自己定义的 state 对象,也就是说是脚本中一个 实例,它的作用域是当前页面,如果再开一个浏览器标签页是取不到的。同理 localstorage 、 sessionStorage 也是一样的。
2、vuex actions 可以执行异步方法,可以返回 promise 。比如 请求api,执行 setTimeout ,使用 dispatch 调用,上面有例子。
3、用新标签页请求一个路由时,代码执行顺序: router( vue 路由守护) => app .created( vue 根实例的 life hook ) => com(路由组件)。所以讲用户状态判断放到路由守卫里。
来源:
https://www.npmjs.com/package/js-cookie
https://vuex.vuejs.org/zh/guide/actions.html