最近閑來無事給自己寫了家庭財務收支管理系統,也就包含支出管理,收入管理和一些統計功能。 先說登錄模塊,因為涉及GET和POST請求,這些東西都是能被監控和抓取的所以就考慮這使用RSA加密解密方式傳輸用戶名和密碼參數,頁面JS如下: 1 /*需要引入三個JS文件,BigInt.js、RSA.js和Ba ...
最近閑來無事給自己寫了家庭財務收支管理系統,也就包含支出管理,收入管理和一些統計功能。
先說登錄模塊,因為涉及GET和POST請求,這些東西都是能被監控和抓取的所以就考慮這使用RSA加密解密方式傳輸用戶名和密碼參數,頁面JS如下:
1 /*需要引入三個JS文件,BigInt.js、RSA.js和Barrett.js,用到cookie則需要引入jquery.cookie.js文件*/ 2 //與後臺交互獲取公鑰 3 function getPublicKey() { 4 var pubKey = ''; 5 if ($.cookie('publicKey') == null) { 6 $.ajax({ 7 url: "/Account/GetRsaPublicKey", 8 type: "get", 9 contentType: "application/x-www-form-urlencoded; charset=utf-8", 10 async: false, 11 data: {}, 12 dataType: "json", 13 success: function (data) { 14 if (data.Code == 0) { 15 pubKey = data.RsaPublicKey + "," + data.Key; 16 $.cookie('publicKey', pubKey, { expires: 1 / 1440 }); 17 } else { 18 Config.Method.JudgeCode(data, 1); 19 } 20 } 21 }); 22 } else { 23 pubKey = $.cookie('publicKey'); 24 } 25 return pubKey; 26 } 27 //公鑰加密用戶密碼Pwd為RSA加密後參數 28 function rsaEncrypt(pwd) { 29 var publicKey = getPublicKey(); 30 setMaxDigits(129); 31 var rsaKey = new RSAKeyPair(publicKey.split(",")[0], "", publicKey.split(",")[1]); 32 var pwdRtn = encryptedString(rsaKey, pwd); 33 return pwdRtn + "," + publicKey.split(",")[2]; 34 } 35 //POST登錄請求,參數 36 <script type="text/javascript"> 37 $(function () { 38 $('#btnSubmit').live('click', function () { 39 var uName = $('#u').val(); 40 var pwd = $('#p').val(); 41 if (uName == '') { 42 alert('用戶名不能為空'); 43 return; 44 } 45 if (pwd == '') { 46 alert('用戶密碼不能為空'); 47 return; 48 } 49 var enPwd = rsaEncrypt(pwd); 50 $.ajax({ 51 type: "POST", 52 url: "/Account/UserLogin", 53 data: { 'UserName': uName, 'Pwd': enPwd.split(",")[0], 'Key': enPwd.split(",")[1], 'RUrl': $('#hiddenUrl').val() }, 54 contentType: "application/x-www-form-urlencoded; charset=utf-8", 55 async: false, 56 dataType: "json", 57 success: function (data) { 58 if (data.result == true) { 59 window.location.href = data.url; 60 return false; 61 } else { 62 $('#msg').text(data.message); 63 } 64 }, 65 error: function (XMLHttpRequest, textStatus, errorThrown) { 66 $('#msg').text(XMLHttpRequest.status + '||' + XMLHttpRequest.readyState + '||' + textStatus); 67 } 68 }); 69 }); 70 }) 71 </script>View Code
前臺加密完成後就需要後臺做解密處理,解密完成後需要使用MD5加密現有密碼與資料庫中用戶密碼進行比較驗證,如果驗證通過則需要寫入cookie以便下次用戶能自 動登錄,由於cookie中我不希望用戶名和密碼都明碼存儲,我這裡用到了AES加密的方式,自定義一個32位的加密密鑰對cookie進行加密解密處理,後臺c#代碼如 下:
1 [HttpPost] 2 public JsonResult UserLogin(string UserName, string Pwd, string Key, string RUrl) 3 { 4 string privateKey = Common.CacheGet(Key) as string; 5 if (!string.IsNullOrEmpty(privateKey)) 6 { 7 if (string.IsNullOrEmpty(UserName)) 8 { 9 return Json(new { result = false, message = "用戶名為空" }, JsonRequestBehavior.AllowGet); 10 } 11 if (string.IsNullOrEmpty(Pwd)) 12 { 13 return Json(new { result = false, message = "用戶密碼為空" }, JsonRequestBehavior.AllowGet); 14 } 15 string pwd = Common.DecryptRSA(Pwd, privateKey);//私鑰解密 16 string md5Pwd = Common.NoneEncrypt(Common.NoneEncrypt(Common.NoneEncrypt(pwd, 1), 1), 1);//將解密後的值md5加密3次 17 AccountUnserInfo userInfo = bll.GetUserInfo(UserName.Trim(), md5Pwd); 18 if (userInfo != null && userInfo.U_Id > 0)//用戶信息存在 19 { 20 //用戶名、密碼放入cookie 21 HttpCookie cookie = new HttpCookie("fw_izz"); 22 //AES加密Cookie 23 cookie["u_name"] = AesEncryptHelper.EncryptAes(UserName); 24 cookie["u_pwd"] = AesEncryptHelper.EncryptAes(pwd); 25 cookie.Expires = DateTime.Now.AddDays(7); 26 Response.Cookies.Add(cookie); 27 if (!string.IsNullOrEmpty(RUrl))//接收隱藏域中的值 28 { 29 return Json(new { result = true, message = "成功", url = RUrl }); 30 } 31 else 32 { 33 return Json(new { result = true, message = "成功", url = "/AccountDetail/Index" }); 34 } 35 } 36 else 37 { 38 return Json(new { result = false, message = "用戶信息不存在", url = "/Account/Index" }); 39 } 40 } 41 else 42 { 43 return Json(new { result = false, message = "非法秘鑰", url = "/Account/Index" }); 44 } 45 }View Code
各種加密解密方法、Cache操作以及cookie操作代碼如下:
1 public class Common 2 { 3 /// <summary> 4 /// 產生一組RSA公鑰、私鑰 5 /// </summary> 6 /// <returns></returns> 7 public static Dictionary<string, string> CreateRsaKeyPair() 8 { 9 var keyPair = new Dictionary<string, string>(); 10 var rsaProvider = new RSACryptoServiceProvider(1024); 11 RSAParameters parameter = rsaProvider.ExportParameters(true); 12 keyPair.Add("PUBLIC", BytesToHexString(parameter.Exponent) + "," + BytesToHexString(parameter.Modulus)); 13 keyPair.Add("PRIVATE", rsaProvider.ToXmlString(true)); 14 return keyPair; 15 } 16 17 /// <summary> 18 /// RSA解密字元串 19 /// </summary> 20 /// <param name="encryptData">密文</param> 21 /// <param name="privateKey">私鑰</param> 22 /// <returns>明文</returns> 23 public static string DecryptRSA(string encryptData, string privateKey) 24 { 25 string decryptData = ""; 26 try 27 { 28 var provider = new RSACryptoServiceProvider(); 29 provider.FromXmlString(privateKey); 30 31 byte[] result = provider.Decrypt(HexStringToBytes(encryptData), false); 32 ASCIIEncoding enc = new ASCIIEncoding(); 33 decryptData = enc.GetString(result); 34 } 35 catch (Exception e) 36 { 37 throw new Exception("RSA解密出錯!", e); 38 } 39 return decryptData; 40 } 41 42 private static string BytesToHexString(byte[] input) 43 { 44 StringBuilder hexString = new StringBuilder(64); 45 46 for (int i = 0; i < input.Length; i++) 47 { 48 hexString.Append(String.Format("{0:X2}", input[i])); 49 } 50 return hexString.ToString(); 51 } 52 53 public static byte[] HexStringToBytes(string hex) 54 { 55 if (hex.Length == 0) 56 { 57 return new byte[] { 0 }; 58 } 59 if (hex.Length % 2 == 1) 60 { 61 hex = "0" + hex; 62 } 63 byte[] result = new byte[hex.Length / 2]; 64 for (int i = 0; i < hex.Length / 2; i++) 65 { 66 result[i] = byte.Parse(hex.Substring(2 * i, 2), System.Globalization.NumberStyles.AllowHexSpecifier); 67 } 68 return result; 69 } 70 71 private static ObjectCache Cache 72 { 73 get { return MemoryCache.Default; } 74 } 75 /// <summary> 76 /// 獲取緩存 77 /// </summary> 78 /// <param name="key"></param> 79 /// <returns></returns> 80 public static object CacheGet(string key) 81 { 82 return Cache[key]; 83 } 84 /// <summary> 85 /// 設置緩存 86 /// </summary> 87 /// <param name="key"></param> 88 /// <param name="data"></param> 89 /// <param name="cacheTime"></param> 90 public static void CacheSet(string key, object data, int cacheTime) 91 { 92 CacheItemPolicy policy = new CacheItemPolicy(); 93 policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime); 94 Cache.Add(new CacheItem(key, data), policy); 95 } 96 /// <summary> 97 /// 判斷緩存是否存在 98 /// </summary> 99 /// <param name="key"></param> 100 /// <returns></returns> 101 public static bool IsSet(string key) 102 { 103 return (Cache[key] != null); 104 } 105 /// <summary> 106 /// 緩存失效 107 /// </summary> 108 /// <param name="key"></param> 109 public static void CacheRemove(string key) 110 { 111 Cache.Remove(key); 112 } 113 /// <summary> 114 /// 對字元串進行加密(不可逆) 115 /// </summary> 116 /// <param name="Password">要加密的字元串</param> 117 /// <param name="Format">加密方式,0 is SHA1,1 is MD5</param> 118 /// <returns></returns> 119 public static string NoneEncrypt(string Password, int Format) 120 { 121 string strResult = ""; 122 switch (Format) 123 { 124 case 0: 125 strResult = FormsAuthentication.HashPasswordForStoringInConfigFile(Password, "SHA1"); 126 break; 127 case 1: 128 strResult = FormsAuthentication.HashPasswordForStoringInConfigFile(Password, "MD5"); 129 break; 130 default: 131 strResult = Password; 132 break; 133 } 134 return strResult; 135 } 136 }View Code