166 lines
5.2 KiB
C#
166 lines
5.2 KiB
C#
|
|
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
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 微信小程序、公众号支付,H5支付 数据签名校验
|
|||
|
|
/// </summary>
|
|||
|
|
public class WxPayChecker: SortedDictionary<string, string>
|
|||
|
|
{
|
|||
|
|
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("<xml>\n");
|
|||
|
|
foreach (var item in this)
|
|||
|
|
{
|
|||
|
|
string key = item.Key;
|
|||
|
|
sb.Append("\t<").Append(key).Append("><![CDATA[").Append(item.Value).Append("]]></").Append(key)
|
|||
|
|
.Append(">\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return sb.Append("</xml>").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;//获取到根节点<xml>
|
|||
|
|
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;//获取到根节点<xml>
|
|||
|
|
XmlNodeList nodes = xmlNode.ChildNodes;
|
|||
|
|
foreach (XmlNode xn in nodes)
|
|||
|
|
{
|
|||
|
|
XmlElement xe = (XmlElement)xn;
|
|||
|
|
this[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中
|
|||
|
|
}
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|