using Hncore.Infrastructure.Common; using Hncore.Infrastructure.Extension; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Xml; namespace Hncore.Pass.PaymentCenter.WxPay.WechatJsPay { /// /// 微信小程序、公众号支付,H5支付 数据签名校验 /// public class WxPayChecker: SortedDictionary { public string SignType { get; set; } = "MD5";// "HMAC-SHA256"; public string MchKey { get; set; } /** * 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数 * @return 时间戳 */ public string GenerateTimeStamp() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); } /** * 生成随机串,随机串包含字母或数字 * @return 随机串 */ public string GenerateNonceStr() { return Guid.NewGuid().ToString("N"); } public virtual string CreateSign() { string sign = ""; foreach (var item in this) { if (item.Key == "sign"|| item.Key == "paySign") continue; sign += item.Key + "=" + item.Value + "&"; } if(this.MchKey.Has()) sign += "key=" + this.MchKey; LogHelper.Trace("CreateSign Str", sign); if (SignType == "MD5") { sign = SecurityHelper.GetMd5Hash(sign); } else if (SignType == "HMAC-SHA256") { sign = CalcHMACSHA256Hash(sign, this.MchKey); } this["sign"] = sign; return sign; } public bool IsSet(string key) { if (!this.ContainsKey(key)) return false; return this[key].Has(); } public virtual bool CheckSign() { //如果没有设置签名,则跳过检测 if (!this.IsSet("sign")) { LogHelper.Error("CheckSign", "签名不存在!"); return false; } //获取接收到的签名 string return_sign = this["sign"]; //在本地计算新的签名 string cal_sign = CreateSign(); if (cal_sign == return_sign) { return true; } return true; } private string CalcHMACSHA256Hash(string plaintext, string salt) { string result = ""; var enc = Encoding.Default; byte[] baText2BeHashed = enc.GetBytes(plaintext), baSalt = enc.GetBytes(salt); System.Security.Cryptography.HMACSHA256 hasher = new HMACSHA256(baSalt); byte[] baHashedText = hasher.ComputeHash(baText2BeHashed); result = string.Join("", baHashedText.ToList().Select(b => b.ToString("x2")).ToArray()); return result; } public string ToXml() { CreateSign(); StringBuilder sb = new StringBuilder("\n"); foreach (var item in this) { string key = item.Key; sb.Append("\t<").Append(key).Append(">\n"); } return sb.Append("").ToString(); } public WxPayChecker FromXml(string xml) { if (string.IsNullOrEmpty(xml)) { return null; } LogHelper.Info("FromXml", xml); this.Clear(); XmlDocument xmlDoc = new XmlDocument() { XmlResolver = null }; xmlDoc.LoadXml(xml); XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点 XmlNodeList nodes = xmlNode.ChildNodes; foreach (XmlNode xn in nodes) { XmlElement xe = (XmlElement)xn; this[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中 } if (!CheckSign()) { return null; } return this; } public WxPayChecker FromXmlNoCheckSign(string xml) { if (string.IsNullOrEmpty(xml)) { return null; } LogHelper.Info("FromXml", xml); this.Clear(); XmlDocument xmlDoc = new XmlDocument() { XmlResolver = null }; xmlDoc.LoadXml(xml); XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点 XmlNodeList nodes = xmlNode.ChildNodes; foreach (XmlNode xn in nodes) { XmlElement xe = (XmlElement)xn; this[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中 } return this; } } }