本人不是专门的程序员,所以代码质量我自己也知道很渣,纯属为了跑通功能写的.
这个是核心的签名过程的类,商户ID和证书序号在支付后台都可以获取
public class HttpHandler : DelegatingHandler
{
private readonly string merchantId; \\商户ID
private readonly string serialNo; \\证书序号
public HttpHandler(string merchantId, string merchantSerialNo)
{
InnerHandler = new HttpClientHandler();
this.merchantId = merchantId;
this.serialNo = merchantSerialNo;
}
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var auth = await BuildAuthAsync(request);
string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
request.Headers.Add("Authorization", value);
//官网的代码没有添加 User-Agent 和 Accept 导致一直报错, 但是api文档里面又提到需要.
request.Headers.Add("User-Agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Mobile Safari/537.36 Edg/119.0.0.0");
request.Headers.Add("Accept", "application/json");
return await base.SendAsync(request, cancellationToken);
}
protected async Task<string> 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 = WxPayTool.Sign(message);
//Sign(message);
return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
}
protected string Sign(string message)
{
// 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY-----
// 亦不包括结尾的-----END PRIVATE KEY-----
string privateKey = @""; //最好是用notepad去打开你腾讯支付后台获取到 apiclient_key.pem, 正式代码可以写个类去读私钥文件的内容,私钥存在指定位置.
byte[] keyData = Convert.FromBase64String(privateKey);
var rsa = RSA.Create();
//适用该方法的版本https://learn.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.asymmetricalgorithm.importpkcs8privatekey?view=net-7.0
rsa.ImportPkcs8PrivateKey(keyData, out _);
byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
}
控制器执行统一下单,并构造jaspi所需要的数据包
public IActionResult pay() {
string prepay_id = "";
OrderData orderData = new OrderData();
orderData.appid = ""; //企业微信ID
orderData.mchid = ""; //商户ID
orderData.description = "";
orderData.out_trade_no = "DF-" + DateTime.Now.ToString("yyyyMMddHHmmssMM");
orderData.notify_url = "";
orderData.attach = "";
orderData.amount = new OrderData.WxPayAmountModel
{
total = 1,
currency = "CNY"
};
orderData.payer = new OrderData.Payer
{
openid = "oKpVN05g3KNRBTWGbPOnzw8Z64Mg"
};
string url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
HttpClient client = new HttpClient(new HttpHandler(" #商户ID# ", " #商户证书序号#"));
var bodyJson = new StringContent(JsonConvert.SerializeObject(orderData).ToString(), Encoding.UTF8, "application/json");
var response = client.PostAsync(url, bodyJson);
var rep = response.Result;//在这里会等待task返回
var respStr = rep.Content.ReadAsStringAsync().Result;
JObject jo = (JObject)JsonConvert.DeserializeObject(respStr);
prepay_id = jo["prepay_id"].ToString();
WxPrePayData prePayData = new WxPrePayData();
prePayData.PrePayBillId = prepay_id;
prePayData.NonceStr = Path.GetRandomFileName();
prePayData.TimeStamp = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
prePayData.PrePayAmount = 1;
prePayData.AppId = "#企业微信ID#";
prePayData.Package = "prepay_id=" + prePayData.PrePayBillId; //这个prepay_id 是统一下单接口返回来的,这里我也折腾了好就才搞明白
string message = prePayData.AppId + "\n" + prePayData.TimeStamp + "\n" + prePayData.NonceStr + "\n" + prePayData.Package + "\n";
prePayData.PaySign = WxPayTool.Sign(message);
ViewData["data"] = prePayData;
return View();
}
public class OrderData
{
public string appid { get; set; }
public string mchid { get; set; }
public string description { get; set; }
public string out_trade_no { get; set; }
public string notify_url { get; set; }
public string attach { set; get; }
public WxPayAmountModel amount { set; get; }
public Payer payer { set; get; }
public class WxPayAmountModel
{
/// <summary>
/// 订单总金额,单位为分。
/// </summary>
public int total { set; get; }
/// <summary>
/// 货币类型,CNY:人民币,境内商户号仅支持人民币。
/// </summary>
public string currency { set; get; } = "CNY";
}
public class Payer {
public string openid { set; get; }
}
}
public class WxPrePayData
{
public string AppId { get; set; }
public string TimeStamp { get; set; }
public string NonceStr { get; set; }
public string Package { get; set; }
public string PaySign { get; set;}
public static string signType = "RSA";
}
支付前端核心js代码直接用的官网上的实例, 我这里是点击id=“pay” 的按钮调用jsapi支付,加载页面前已经完成了统一下单过程.
$("#pay").click(function () {
function onBridgeReady() {
WeixinJSBridge.invoke('getBrandWCPayRequest', {
"appId": "@data.AppId", //公众号ID,由商户传入
"timeStamp": "@data.TimeStamp", //时间戳,自1970年以来的秒数
"nonceStr": "@data.NonceStr", //随机串
"package": "@data.Package",
"signType": "RSA", //微信签名方式:
"paySign": "@Html.Raw(data.PaySign)" //微信签名
},
function (res) {
alert(res.err_msg);
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
});
}
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
onBridgeReady();
}
})
另外就是控制器需要和你在支付后台设置的jsapi的目录保持一致的.
文章浏览阅读7.4w次,点赞13次,收藏25次。位(bit) 一位二进制数,又称比特字节(byte) 1B = 8b 内存存储的最小单元字长:同一时间内,计算机能处理的二进制位数字长决定了计算机的运算精度,字长越长,计算机的运算精度就越高。因此,高性能的计算机,其字长较长,而性能较差的计算机,其字长相对要短一些。 其次,字长决定了指令直接寻址的能力。一般机器的字长都是字节的1、2、4、8倍。微机的字长为8位、16_8进制46.5转换为二进制
文章浏览阅读5.3k次,点赞6次,收藏15次。Ruoyi-Cloud报错统计端口工具项目测试ruoyi官网常见问题端口Web server failed to start. Port 端口 was already in use.( Web服务器无法启动。端口8080已在使用中。)解决:打开cmd: netstat -ano | findstr 8080TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 9824TCP [::]:8080 _若依 no message available
文章浏览阅读972次。(6)评论表(comment): 存储用户评论信息,如评论ID、用户ID、视频ID、评论内容、评论时间等。(1)用户表(user):存储用户信息,如用户ID、用户名、密码、性别、年龄、地区、注册时间等。
文章浏览阅读2.9w次,点赞59次,收藏488次。Postman接口测试——我看过最详细+全面的文章教程了【转载】_postman接口测试
文章浏览阅读6.6w次,点赞21次,收藏35次。@RequestMapping("/hello") public String hello(Model map){ // 将要遍历的map Map user= new HashMap(); user.put("name", "姓名"); user.put("age", "年龄"); user.put("sex", "性别"); user.put("birth..._thymeleaf遍历list
文章浏览阅读817次,点赞20次,收藏18次。作为一名即将求职的程序员,面对一个可能跟近些年非常不同的 2019 年,你的就业机会和风口会出现在哪里?在这种新环境下,工作应该选择大厂还是小公司?已有几年工作经验的老兵,又应该如何保持和提升自身竞争力,转被动为主动?就目前大环境来看,跳槽成功的难度比往年高很多。一个明显的感受:今年的面试,无论一面还是二面,都很考验Java程序员的技术功底。最近我整理了一份复习用的面试题及面试高频的考点题及技术点梳理成一份“Java经典面试问题(含答案解析).pdf和一份网上搜集的“Java程序员面试笔试真题库.pdf。
文章浏览阅读1k次,点赞2次,收藏2次。纯软件/半虚拟化/直接分配三种I/O虚拟化方案的对比、virtio实现I/O半虚拟化的原理、气球技术的作用和原理、V2V在线迁移的特点、作用及KVM中的运行步骤、KVM虚拟化的安全技术架构、QEMU monitor的基本使用_迁移virt-v2v -ic qemu+ssh://192.168.2.87/system -o local -os /root/dcaaslab/
文章浏览阅读8.1k次。如题_dedecms57sp2漏洞
文章浏览阅读698次,点赞20次,收藏25次。随着编程教育的普及,如何确保教学质量,如何让青少年在学习编程的过程中获得最佳的学习体验和知识掌握,是教育者和家长共同关心的问题。教学评价“1287e”的开发和应用,不仅能够帮助教师了解教学过程中的优势和不足,还能够为学生提供个性化的学习反馈,从而促进学生的个性化发展。从长远来看,青少年编程课程的教学评价不仅对提升当前的教学效果具有重要意义,对于培养未来社会所需的创新人才也具有深远的影响。探讨和实施有效的教学评价机制,对于推动青少年编程教育的发展,乃至整个教育体系的创新都具有重要意义。
文章浏览阅读824次。<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>插入内容为HTML代码</title> <script src="../js/vue.js"></script></head><body> <div id="app"> <h2&g._js 操作dom 插入html
文章浏览阅读6.6k次,点赞37次,收藏24次。选择合适的软路由应基于实际需求和使用场景,对于普通用户和专业用户来说,不同的软路由可能有不同的优势和适用性。最终选择应当考虑网络功能、易用性、稳定性以及所需的特定功能需求。_routeros和爱快哪个强大
文章浏览阅读6.2w次,点赞8次,收藏20次。iText5.x版本以上中的font和encoding文件都是从String RESOURCE_PATH = “com/itextpdf/text/pdf/fonts/”加载的,而itextasian1.5.x.jar的包名是com.lowagie.text.pdf.fonts, 包名不一致,导致路径错误。解决方法如下: 1.将itextasian1.5.x.ja解压,找到里面itextasi......_font 'stsong-light' with 'unigb-ucs2-h' is not recognized.