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;
|
||
}
|
||
|
||
}
|
||
} |