.Net|.Net Core微信服务商二次进件的开发
最近商城进行微信服务商二次进件的开发,大致有几个点
一,服务商签名
二,服务商证书获取
三,图片上传
四,敏感信息加密
五,查询进件状态
除此之外,就是进件信息的拼装
文章图片
电商二级商户进件申请单-状态流转
文章图片
一 服务商签名
首先准备必须的配置:商户号、证书、秘钥、小程序appid、appsecret
#region 服务商签名private string SrvPayBuildAuthAsync(string uri, string body, string method = "POST"){var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds(); string nonce = Guid.NewGuid().ToString(); string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n"; string signature = SrvSign(message); return $"mchid=\"{_wxCfg.SrvPayMerchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{_wxCfg.SrvPayCertNo}\",signature=\"{signature}\""; }private string SrvSign(string message){var bytes = Utils.ReadBytesIfExist(_wxCfg.SrvPayCertFile); if (bytes is null){return ""; }X509Certificate2 cert = new(bytes, _wxCfg.SrvPayMerchantId); RSA rsa = cert.GetRSAPrivateKey(); var signData = https://www.it610.com/article/rsa.SignData(Encoding.UTF8.GetBytes(message), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); return Convert.ToBase64String(signData); }
二 获取证书 分为:第一步获取证书,第二步解密证书
1 获取证书
https://api.mch.weixin.qq.com/v3/certificates
#region 获取平台证书public async TaskGetSrvCert(){string uri = "/v3/certificates"; var auth = SrvPayBuildAuthAsync(uri, "", "GET"); var header = new Dictionary{{ "Authorization",$"WECHATPAY2-SHA256-RSA2048 {auth}"},{ "Accept","*/*" },{ "Accept-Encoding","gzip,deflate,brn" },{ "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.46" },}; return await GetUrlAsync (uri, header); }#endregion
使用的实体:CertificatesOutModel
public sealed class CertificatesOutModel : IWXResponse{[JsonPropertyName("data")]public IEnumerableData { get; set; }public string Code { get; set; }public string Message { get; set; }}public class Certificates{[JsonPropertyName("serial_no")]public string SerialNo { get; set; }[JsonPropertyName("effective_time")]public string EffectiveTime { get; set; }[JsonPropertyName("expire_time")]public string ExpireTime { get; set; }[JsonPropertyName("encrypt_certificate")]public EncryptCertificate EncryptCertificate { get; set; }}
请求方法:GetUrlAsync
protected async TaskGetUrlAsync (string url, Dictionary headers = null){HttpResponseMessage res = null; try{if (headers != null && headers.Count > 0){foreach (var header in headers){_client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value); }}res = await _client.GetAsync(url); res.EnsureSuccessStatusCode(); var result = await res.Content.ReadAsStringAsync(); if (result == null){return default; }return result.ToJson (); }catch{var result = await res.Content.ReadAsStringAsync(); if (result == null){return default; }return result.ToJson (); }}
解密方法
//获取证书var cert = await _wxClient.GetSrvCert(); var certificateModel = cert.Data.FirstOrDefault(); if (!cert.Data.Any()){return new MKResult(code: 400, msg: "未获取到平台证书"); }if (!string.IsNullOrEmpty(applyment.Body.SerialNo)){certificateModel = cert.Data.SingleOrDefault(s => s.SerialNo == applyment.Body.SerialNo); }certificateModel.EncryptCertificate.Ciphertext = AESUtility.AesGcmDecrypt(_wxCfg.SrvApiV3Key,certificateModel.EncryptCertificate.AssociatedData,certificateModel.EncryptCertificate.Nonce,certificateModel.EncryptCertificate.Ciphertext);
三,上传图片 因为我的图片保存在oss,首先要网络图片Bytes,对图片进行sha256,方法在后面
protected async TaskGetUrlBytesAsync(string url, Dictionary headers = null){try{if (headers != null && headers.Count > 0){foreach (var header in headers){_client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value); }}var res = await _client.GetAsync(url); res.EnsureSuccessStatusCode(); return await res.Content.ReadAsByteArrayAsync(); }catch{return default; }}
然后上传图片
/// /// 上传图片/// /// ///public async Task > UploadFile(string url){string fileContentType; string filetype; if (url!.Contains(".bmp", StringComparison.OrdinalIgnoreCase)){fileContentType = "image/bmp"; filetype = ".bmp"; }else if (url!.Contains(".jpg", StringComparison.OrdinalIgnoreCase)){fileContentType = "image/jpeg"; filetype = ".jpg"; }else if (url!.Contains(".jpeg", StringComparison.OrdinalIgnoreCase)){fileContentType = "image/jpeg"; filetype = ".jpeg"; }else{fileContentType = "image/png"; filetype = ".png"; }UploadMerchantMediaImageRequest meta = new(); var fileBytes = await GetUrlBytesAsync(url); //获取网络图片Bytesif ((fileBytes?.Length ?? 0) == 0){return new MKResult (code: 400, msg: "转换图片失败"); }meta.FileHash = GetHash(fileBytes); meta.FileName = Guid.NewGuid().ToString("N").ToLower() + filetype; string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x"); using var fileContent = new ByteArrayContent(fileBytes); using var metaContent = new StringContent(meta.ToJson(), Encoding.UTF8, "application/json"); using var httpContent = new MultipartFormDataContent(boundary); httpContent.Add(metaContent, "\"meta\""); //meta 必须要加双引号httpContent.Add(fileContent, "\"file\"", "\"" + meta.FileName + "\""); //必须要加双引号httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary); // boundary不能加引号metaContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(fileContentType); var uri = $"/v3/merchant/media/upload"; var res = await V3UpLoadFile (uri, meta.ToJson(), httpContent); return new MKResult (res, 1); }
private async TaskV3UpLoadFile (string uri, string meta, MultipartFormDataContent content){var auth = SrvPayBuildAuthAsync(uri, meta); var header = new Dictionary{{ "Authorization",$"WECHATPAY2-SHA256-RSA2048 {auth}"},{ "Accept","*/*" },{ "Accept-Encoding","gzip,deflate,brn" },{ "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.46" },}; return await V3PostFileAsync (uri, header, content); }
protected async TaskV3PostFileAsync (string url, Dictionary headers, MultipartFormDataContent content){HttpResponseMessage res = null; try{if (headers != null && headers.Count > 0){foreach (var header in headers){_client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value); }}res = await _client.PostAsync(url, content); res.EnsureSuccessStatusCode(); var result = await res.Content.ReadAsStringAsync(); if (result == null){return default; }return result.ToJson (); }catch{var result = await res.Content.ReadAsStringAsync(); if (result == null){return default; }return result.ToJson (); }finally{if (content != null){content.Dispose(); }}}
#region 二进制内容进行sha256private static string GetHash(byte[] bytes){if (bytes == null) throw new ArgumentNullException(nameof(bytes)); using SHA256 sha = SHA256.Create(); byte[] hashBytes = sha.ComputeHash(bytes); return BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); }
四,敏感信息加密 使用获取到的证书certificateModel,进行加密
public static class RSAUtility{public static string RSAEncrypt(string text, Certificates certificateModel){var bytes = Encoding.UTF8.GetBytes(certificateModel.EncryptCertificate.Ciphertext); using var x509 = new X509Certificate2(bytes); var rsaParam = x509.GetRSAPublicKey().ExportParameters(false); var rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(rsaParam); var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), true); return Convert.ToBase64String(buff); }}
五,查询进件状态 直接使用进件返回的Id,调用接口查询就Ok了
【.Net|.Net Core微信服务商二次进件的开发】到此这篇关于.Net Core微信服务商二次进件的文章就介绍到这了,更多相关.Net Core微信服务商内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- 基于微信小程序带后端ssm接口小区物业管理平台设计
- 员工的微信朋友圈是公司的宣传阵地吗()
- FBI怎么和恐怖分子谈判
- 分享!如何分分钟实现微信扫二维码调用外部浏览器打开指定页面的功能
- 关于Core|关于Core Image
- 微信小程序基础知识
- ASP.NET|ASP.NET Core应用开发思维导图
- 使用Promise对微信小程序wx.request请求方法进行封装
- 茶事|茶事 | 单丛里的一泡奇葩
- 微信小程序请求接口格式