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(">").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;
}
}
}