发布:2023/3/28 20:24:02作者:管理员 来源:本站 浏览次数:940
关于API v3
为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付API v3。
相较于之前的微信支付API,主要区别是:
遵循统一的REST的设计风格
使用JSON作为数据交互的格式,不再使用XML
使用基于非对称密钥的SHA256-RSA的数字签名算法,不再使用MD5或HMAC-SHA256
不再要求携带HTTPS客户端证书(仅需携带证书序列号)
使用AES-256-GCM,对回调中的关键信息进行加密保护
如下方法转载:
.Net Core 微信H5支付API V3【统一下单,回调】_平庸的俗人的博客-CSDN博客
统一下单的方法
public class H5MyWXPayUtil
{
public readonly static string appid = “”// 这里填写你自己的appid
// 商户号
public readonly static string mch_id = “”;// 这里填写你自己的商户号
// 商户秘钥
public readonly static string partnerkey = “”// 这里填写你自己的商户秘钥
// 回调地址
public readonly static string notifyurl = “”// 回调地址随便外网能访问就行 /tPosition/WX_Callback
// 统一下单接口
public readonly static string url = "https://api.mch.weixin.qq.com/v3/pay/transactions/h5";
#region H5请求的需要的参数
/// <summary>
/// h5支付需要的类
/// </summary>
public class bodyModel {
/// <summary>
/// 直连商户号
/// </summary>
public string mchid { get; set; }
/// <summary>
/// 应用ID
/// </summary>
public string appid { get; set; }
/// <summary>
/// 商品描述
/// </summary>
public string description { get; set; }
/// <summary>
/// 商户订单号
/// </summary>
public string out_trade_no { get; set; }
/// <summary>
/// 通知地址
/// </summary>
public string notify_url { get; set; }
/// <summary>
/// 订单金额
/// </summary>
public object amount { get; set; }
/// <summary>
/// 景信息
/// </summary>
public object scene_info { get; set; }
/// <summary>
/// 附加数据
/// </summary>
public string attach { get; set; }
}
public class H5amount {
/// <summary>
/// 金钱
/// </summary>
public int total { get; set; }
}
/// <summary>
/// 场景信息
/// </summary>
public class H5scene_info {
/// <summary>
/// 客户端IP
/// </summary>
public string payer_client_ip { get; set; }
/// <summary>
/// H5场景信息
/// </summary>
public object h5_info { get; set; }
}
/// <summary>
/// H5场景信息
/// </summary>
public class H5type {
/// <summary>
/// 场景类型
/// </summary>
public string type { get; set; }
}
#endregion
#region 请求返回的参数
public class returnParameters {
/// <summary>
/// 返回结果【Success/Error】
/// </summary>
public bool result { get; set; }
/// <summary>
/// 描述
/// </summary>
public string errmsg { get; set; }
/// <summary>
/// 返回成功的链接
/// </summary>
public string h5_url { get; set; }
}
#endregion
/// <summary>
/// H5支付封装
/// </summary>
/// <param name="description">商品的描述</param>
/// <param name="total">金钱,分为单位</param>
/// <param name="attach">附加数据</param>
/// <param name="payer_client_ip">客户端的ip地址</param>
/// <returns></returns>
public static string H5Getprepay(string description, decimal total, string attach,string payer_client_ip) {
returnParameters returnParameters = new returnParameters();
//body参数
var formData = new bodyModel
{
appid=appid,//应用ID
mchid=mch_id,//商户号
description= description,//商品描述
out_trade_no = getRandomTime(),//商户订单号
attach =attach,//附加数据
notify_url=notifyurl,//通知地址
amount =new H5amount {
total= Convert.ToInt32(total * 100),//金额
},
scene_info =new H5scene_info {
payer_client_ip= payer_client_ip,//客户端Ip
h5_info=new H5type {
type= "Wap"
}
}
};
HttpClient client = new HttpClient(new HttpHandlerH5("{商户号}", "{商户证书序列号}"));
var bodyJson = new StringContent(formData.ToJson(), Encoding.UTF8, "application/json");
var response = client.PostAsync(url, bodyJson);
var rep = response.Result;//在这里会等待task返回
var respStr = rep.Content.ReadAsStringAsync();
string responseBodyAsText = respStr.Result;
JObject jo = (JObject)JsonConvert.DeserializeObject(responseBodyAsText);
if (response.Result.IsSuccessStatusCode)
{
returnParameters.h5_url = jo["h5_url"].ToString();
returnParameters.result = true;
}
else
{
returnParameters.errmsg = jo["message"].ToString();
returnParameters.result = false;
}
return JsonConvert.SerializeObject(returnParameters);
}
/// 生成订单号
/// </summary>
/// <returns></returns>
private static string getRandomTime()
{
Random rd = new Random();//用于生成随机数
string DateStr = DateTime.Now.ToString("yyyyMMddHHmmssMM");//日期
string str = DateStr + rd.Next(10000).ToString().PadLeft(4, '0');//带日期的随机数
return str;
}
}
签名生成
using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
namespace HttpHandlerDemo
{
// 使用方法
// HttpClient client = new HttpClient(new HttpHandler("{商户号}", "{商户证书序列号}"));
// ...
// var response = client.GetAsync("https://api.mch.weixin.qq.com/v3/certificates");
public class HttpHandler : DelegatingHandler
{
private readonly string merchantId;
private readonly string serialNo;
public HttpHandler(string merchantId, string merchantSerialNo)
{
InnerHandler = new HttpClientHandler();
this.merchantId = merchantId;
this.serialNo = merchantSerialNo;
}
protected async override Task SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var auth = await BuildAuthAsync(request);
string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
request.Headers.Add("Authorization", value);
return await base.SendAsync(request, cancellationToken);
}
protected async Task BuildAuthAsync(HttpRequestMessage request)
{
string method = request.Method.ToString();
string body = "";
if (method == "POST" || method == "PUT" || method == "PATCH")
{
var content = request.Content;
body = await content.ReadAsStringAsync();
}
string uri = request.RequestUri.PathAndQuery;
var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
string nonce = Path.GetRandomFileName();
string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
string signature = Sign(message);
return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
}
protected string Sign(string message)
{
// NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY-----
// 亦不包括结尾的-----END PRIVATE KEY-----
string privateKey = "{你的私钥}";
byte[] keyData = Convert.FromBase64String(privateKey);
using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
using (RSACng rsa = new RSACng(cngKey))
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
}
}
}
}
支付回调方法:
public async Task<string> PayH5NotifyUrl()
{
//获取回调POST过来的xml数据的代码
Stream stream = HttpContext.Request.Body;
byte[] buffer = new byte[HttpContext.Request.ContentLength.Value];
await stream.ReadAsync(buffer, 0, buffer.Length); //.net core 3.1需要用ReadAsync才不会出错
string str = System.Text.Encoding.UTF8.GetString(buffer);
JObject jsonObj = JObject.Parse(str);
string summary = jsonObj["summary"].ToString();//回调摘要
if (summary== "支付成功")
{
string associatedData = ((JObject)jsonObj["resource"])["associated_data"].ToString();//附加数据
string nonce = ((JObject)jsonObj["resource"])["nonce"].ToString();//随机串
string ciphertext = ((JObject)jsonObj["resource"])["ciphertext"].ToString();//数据密文
//调用解密
var decryptStr = AesGcm.AesGcmDecrypt(associatedData, nonce, ciphertext);
JObject resource = JObject.Parse(decryptStr);
string attach = resource["attach"].ToString();//附加数据
string out_trade_no= resource["out_trade_no"].ToString();//商户订单号
string transaction_id = resource["transaction_id"].ToString();//信支付订单号
string total_fee = ((JObject)resource["amount"])["total"].ToString();//总金额
string return_code = resource["trade_state"].ToString();//交易状态
try
{
//业务逻辑
if (return_code.ToUpper()== "SUCCESS")
{
return "{"
+ "\"code\":\"SUCCESS\","
+ "\"message\":\"成功\","
+ "}";
}
}
catch (Exception e)
{
throw;
}
}
return "{"
+ "\"code\":\"FAIL\","
+ "\"message\":\"ERROR\","
+ "}";
}
解密方法:
public class AesGcm
{
private static string ALGORITHM = "AES/GCM/NoPadding";
private static int TAG_LENGTH_BIT = 128;
private static int NONCE_LENGTH_BYTE = 12;
private static string AES_KEY = "yourkeyhere";//APIv3密钥
public static string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
{
GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
AeadParameters aeadParameters = new AeadParameters(
new KeyParameter(Encoding.UTF8.GetBytes(AES_KEY)),
128,
Encoding.UTF8.GetBytes(nonce),
Encoding.UTF8.GetBytes(associatedData));
gcmBlockCipher.Init(false, aeadParameters);
byte[] data = Convert.FromBase64String(ciphertext);
byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
gcmBlockCipher.DoFinal(plaintext, length);
return Encoding.UTF8.GetString(plaintext);
}
}
常见问题:
© Copyright 2014 - 2024 柏港建站平台 ejk5.com. 渝ICP备16000791号-4