千家信息网

如何理解.Net Core微信服务商二次进件的开发

发表于:2024-12-03 作者:千家信息网编辑
千家信息网最后更新 2024年12月03日,这篇文章主要介绍"如何理解.Net Core微信服务商二次进件的开发",在日常操作中,相信很多人在如何理解.Net Core微信服务商二次进件的开发问题上存在疑惑,小编查阅了各式资料,整理出简单好用的
千家信息网最后更新 2024年12月03日如何理解.Net Core微信服务商二次进件的开发

这篇文章主要介绍"如何理解.Net Core微信服务商二次进件的开发",在日常操作中,相信很多人在如何理解.Net Core微信服务商二次进件的开发问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何理解.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 = 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 Task GetSrvCert()        {            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 IEnumerable Data { 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 Task GetUrlAsync(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 Task GetUrlBytesAsync(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);//获取网络图片Bytes            if ((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 Task V3UpLoadFile(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 Task V3PostFileAsync(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 二进制内容进行sha256        private 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 Core微信服务商二次进件的开发"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0