欢迎光临
我们一直在努力

.net 微信小程序支付成功后通知解密

本篇文章记录一下微信小程序支付功能,支付成功后接收通知时的解决代码

1、准备工作,需要引入以下

必须引dll  BouncyCastle.Crypto.dll

using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Engines;
using System.Text;
using Org.BouncyCastle.Crypto.Parameters;

 

2、获取post传过来的body文本

            System.IO.Stream s = HttpContext.Current.Request.InputStream;
            int count = 0;
            byte[] buffer = new byte[1024];
            StringBuilder builder = new StringBuilder();
            while ((count = s.Read(buffer, 0, 1024)) > 0)
            {
                builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
            }
            s.Flush();
            s.Close();
            s.Dispose();
            var str = builder.ToString();
//转换成对象实体
WxPayNotifyModel wxPayNotify = Newtonsoft.Json.JsonConvert.DeserializeObject<WxPayNotifyModel>(ReadStr);
//开始解密
AesGcmDecryptByBouncyCastle("这里是商户平台上设置的APIv3密钥", wxPayNotify.resource.nonce, wxPayNotify.resource.ciphertext, wxPayNotify.resource.associated_data)

 

3、c# 加解密相关代码,  支付通知里只需要解密的方法  AesGcmDecryptByBouncyCastle

/// <summary>
    /// 使用BouncyCastle进行AEAD_AES_256_GCM 解密
    /// </summary>
    /// <param name="key">key:32位字符</param>
    /// <param name="nonce">随机串12位</param>
    /// <param name="cipherData">密文(Base64字符)</param>
    /// <param name="associatedData">附加数据可能null</param>
    /// <returns></returns>
    static string AesGcmDecryptByBouncyCastle(string key, string nonce, string cipherData, string associatedData)
    {
        var associatedBytes = associatedData == null ? null : Encoding.UTF8.GetBytes(associatedData);

        var gcmBlockCipher = new GcmBlockCipher(new AesEngine());
        var parameters = new AeadParameters(
            new KeyParameter(Encoding.UTF8.GetBytes(key)),
            128,  //128 = 16 * 8 => (tag size * 8)
            Encoding.UTF8.GetBytes(nonce),
            associatedBytes);
        gcmBlockCipher.Init(false, parameters);

        var data = Convert.FromBase64String(cipherData);
        var plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];

        var length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
        gcmBlockCipher.DoFinal(plaintext, length);
        return Encoding.UTF8.GetString(plaintext);
    }

    /// <summary>
    /// 使用BouncyCastle进行AEAD_AES_256_GCM 加密
    /// </summary>
    /// <param name="key">key32位字符</param>
    /// <param name="nonce">随机串12位</param>
    /// <param name="plainData">明文</param>
    /// <param name="associatedData">附加数据可能null</param>
    /// <returns></returns>
    static string AesGcmEncryptByBouncyCastle(string key, string nonce, string plainData, string associatedData)
    {
        var associatedBytes = associatedData == null ? null : Encoding.UTF8.GetBytes(associatedData);

        var gcmBlockCipher = new GcmBlockCipher(new AesEngine());
        var parameters = new AeadParameters(
            new KeyParameter(Encoding.UTF8.GetBytes(key)),
            128, //128 = 16 * 8 => (tag size * 8)
            Encoding.UTF8.GetBytes(nonce),
            associatedBytes);
        gcmBlockCipher.Init(true, parameters);

        var data = Encoding.UTF8.GetBytes(plainData);
        var cipherData = new byte[gcmBlockCipher.GetOutputSize(data.Length)];

        var length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, cipherData, 0);
        gcmBlockCipher.DoFinal(cipherData, length);
        return Convert.ToBase64String(cipherData);
    }

 

4、需要的实体代码

/// <summary>
/// 微信支付结果回调通知实体
/// </summary>
public class WxPayNotifyModel
{
    /// <summary>
    /// 通知的唯一ID
    /// </summary>
    public string id { set; get; }

    /// <summary>
    /// 通知创建时间,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。
    /// </summary>
    public string create_time { set; get; }

    /// <summary>
    /// 通知的类型,支付成功通知的类型为TRANSACTION.SUCCESS
    /// </summary>
    public string event_type { set; get; }

    /// <summary>
    /// 通知的资源数据类型,支付成功通知为encrypt-resource
    /// </summary>
    public string resource_type { set; get; }

    /// <summary>
    /// 通知资源数据,json格式
    /// </summary>
    public WxPayResourceModel resource { set; get; }

    /// <summary>
    /// 回调摘要
    /// </summary>
    public string summary { set; get; }
}

/// <summary>
/// 微信支付回调通知结果resource实体
/// </summary>
public class WxPayResourceModel
{
    /// <summary>
    /// 对开启结果数据进行加密的加密算法,目前只支持AEAD_AES_256_GCM
    /// </summary>
    public string algorithm { set; get; }

    /// <summary>
    /// Base64编码后的开启/停用结果数据密文
    /// </summary>
    public string ciphertext { set; get; }

    /// <summary>
    /// 附加数据
    /// </summary>
    public string associated_data { set; get; }

    /// <summary>
    /// 原始回调类型,为transaction
    /// </summary>
    public string original_type { set; get; }

    /// <summary>
    /// 加密使用的随机串
    /// </summary>
    public string nonce { set; get; }
}

/// <summary>
/// 微信支付回调通知结果解密实体
/// </summary>
public class WxPayResourceDecryptModel
{
    /// <summary>
    /// 直连商户申请的公众号或移动应用appid
    /// </summary>
    public string appid { set; get; }

    /// <summary>
    /// 商户的商户号,由微信支付生成并下发。
    /// </summary>
    public string mchid { set; get; }

    /// <summary>
    /// 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。特殊规则:最小字符长度为6
    /// </summary>
    public string out_trade_no { set; get; }

    /// <summary>
    /// 微信支付系统生成的订单号。
    /// </summary>
    public string transaction_id { set; get; }

    /// <summary>
    /// 交易状态,枚举值:
    /// SUCCESS:支付成功
    /// REFUND:转入退款
    /// NOTPAY:未支付
    /// CLOSED:已关闭
    /// REVOKED:已撤销(付款码支付)
    /// USERPAYING:用户支付中(付款码支付)
    /// PAYERROR:支付失败(其他原因,如银行返回失败)
    /// ACCEPT:已接收,等待扣款
    /// </summary>
    public string trade_state { get; set; }

    /// <summary>
    /// 交易状态描述
    /// </summary>
    public string trade_state_desc { get; set; }

    /// <summary>
    /// 支付者信息
    /// </summary>
    public WxPayerResourceDecryptModel payer { set; get; }

}

/// <summary>
/// 支付用户信息实体
/// </summary>
public class WxPayerResourceDecryptModel
{
    /// <summary>
    /// 用户在直连商户appid下的唯一标识。
    /// </summary>
    public string openid { get; set; }
}

 

异常以及解决方案: 错误:mac check in GCM failed   这个异常不是代码错误是,是解密失败。 特别特别要检查商户平台上设置的APIv3密钥是否正确。检查解密函数中参数是否正确。

注,只要代码编译通过就不会出异常

“/”应用程序中的服务器错误。
mac check in GCM failed
说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息: Org.BouncyCastle.Crypto.InvalidCipherTextException: mac check in GCM failed

 

 

 

赞(0)
未经允许不得转载:自游互动 » .net 微信小程序支付成功后通知解密
分享到: 更多 (0)

自由技术,自由自在

项目合作联系我们