.Net Core微信服务商二次进件的开发

 更新时间:2021年10月23日 00:00  点击:1777 作者:偏执的光辉岁月

最近商城进行微信服务商二次进件的开发,大致有几个点

一,服务商签名

二,服务商证书获取

三,图片上传

四,敏感信息加密

五,查询进件状态

除此之外,就是进件信息的拼装

电商二级商户进件申请单-状态流转

一 服务商签名

首先准备必须的配置:商户号、证书、秘钥、小程序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<CertificatesOutModel> GetSrvCert()
        {
            string uri = "/v3/certificates";
            var auth = SrvPayBuildAuthAsync(uri, "", "GET");
            var header = new Dictionary<string, string>
            {
                { "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<CertificatesOutModel>(uri, header);
        }
        #endregion

使用的实体:CertificatesOutModel

public sealed class CertificatesOutModel : IWXResponse
    {
        [JsonPropertyName("data")]
        public IEnumerable<Certificates> 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<T> GetUrlAsync<T>(string url, Dictionary<string, string> 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<T>();
            }
            catch
            {
                var result = await res.Content.ReadAsStringAsync();
                if (result == null)
                {
                    return default;
                }
                return result.ToJson<T>();
            }
        }

解密方法

//获取证书
            var cert = await _wxClient.GetSrvCert();
            var certificateModel = cert.Data.FirstOrDefault();
            if (!cert.Data.Any())
            {
                return new MKResult<V3WXPayApplymentIdOutModel>(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<byte[]> GetUrlBytesAsync(string url, Dictionary<string, string> 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;
            }
        }

然后上传图片

/// <summary>
        /// 上传图片
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public async Task<MKResult<V3WXPayFileUploadOutModel>> 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<V3WXPayFileUploadOutModel>(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<V3WXPayFileUploadOutModel>(uri, meta.ToJson(), httpContent);
            return new MKResult<V3WXPayFileUploadOutModel>(res, 1);
        }

private async Task<T> V3UpLoadFile<T>(string uri, string meta, MultipartFormDataContent content)
        {
            var auth = SrvPayBuildAuthAsync(uri, meta);
            var header = new Dictionary<string, string>
            {
                { "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<T>(uri, header, content);
        }

protected async Task<T> V3PostFileAsync<T>(string url, Dictionary<string, string> 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<T>();
            }
            catch
            {
                var result = await res.Content.ReadAsStringAsync();
                if (result == null)
                {
                    return default;
                }
                return result.ToJson<T>();
            }
            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微信服务商二次进件的文章就介绍到这了,更多相关.Net Core微信服务商内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

原文出处:https://www.cnblogs.com/liuYingwei/p/15437991.html

[!--infotagslink--]

相关文章

  • ASP.NET购物车实现过程详解

    这篇文章主要为大家详细介绍了ASP.NET购物车的实现过程,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-22
  • .NET Core下使用Kafka的方法步骤

    这篇文章主要介绍了.NET Core下使用Kafka的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • 在ASP.NET 2.0中操作数据之七十二:调试存储过程

    在开发过程中,使用Visual Studio的断点调试功能可以很方便帮我们调试发现程序存在的错误,同样Visual Studio也支持对SQL Server里面的存储过程进行调试,下面就让我们看看具体的调试方法。...2021-09-22
  • Win10 IIS 安装.net 4.5的方法

    这篇文章主要介绍了Win10 IIS 安装及.net 4.5及Win10安装IIS并配置ASP.NET 4.0的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-22
  • C#微信开发之发送模板消息

    这篇文章主要为大家详细介绍了C#微信开发之发送模板消息的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • iOS新版微信底部返回横条问题的解决

    这篇文章主要介绍了iOS新版微信底部返回横条问题的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-30
  • 详解.NET Core 3.0 里新的JSON API

    这篇文章主要介绍了详解.NET Core 3.0 里新的JSON API,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • .net数据库操作框架SqlSugar的简单入门

    这篇文章主要介绍了.net数据库操作框架SqlSugar的简单入门,帮助大家更好的理解和学习使用.net技术,感兴趣的朋友可以了解下...2021-09-22
  • ASP.NET Core根据环境变量支持多个 appsettings.json配置文件

    这篇文章主要介绍了ASP.NET Core根据环境变量支持多个 appsettings.json配置文件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • 记一次EFCore类型转换错误及解决方案

    这篇文章主要介绍了记一次EFCore类型转换错误及解决方案,帮助大家更好的理解和学习使用asp.net core,感兴趣的朋友可以了解下...2021-09-22
  • 基于C#实现微信支付宝扫码支付功能

    为公司系统业务需要,这几天了解了一下微信和支付宝扫码支付的接口,并用c#实现了微信和支付宝扫码支付的功能。需要的朋友跟随小编一起看看吧...2020-06-25
  • Python爬取微信小程序通用方法代码实例详解

    这篇文章主要介绍了Python爬取微信小程序通用方法代码实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-29
  • C#实现的微信网页授权操作逻辑封装示例

    这篇文章主要介绍了C#实现的微信网页授权操作逻辑封装,分析了微信网页授权操作的原理、步骤并给出了C#实现的网页授权操作逻辑封装类,需要的朋友可以参考下...2020-06-25
  • iOS新版微信底部工具栏遮挡问题完美解决

    这篇文章主要介绍了iOS新版微信底部工具栏遮挡问题完美解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-30
  • C#图像识别 微信跳一跳机器人

    这篇文章主要为大家详细介绍了C#图像识别,微信跳一跳机器人,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • 详解ASP.NET Core 中基于工厂的中间件激活的实现方法

    这篇文章主要介绍了ASP.NET Core 中基于工厂的中间件激活的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-22
  • C#使用Ado.Net更新和添加数据到Excel表格的方法

    这篇文章主要介绍了C#使用Ado.Net更新和添加数据到Excel表格的方法,较为详细的分析了OLEDB的原理与使用技巧,可实现较为方便的操作Excel数据,需要的朋友可以参考下...2020-06-25
  • .NET C#利用ZXing生成、识别二维码/条形码

    ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口。这篇文章主要给大家介绍了.NET C#利用ZXing生成、识别二维码/条形码的方法,文中给出了详细的示例代码,有需要的朋友们可以参考借鉴。...2020-06-25
  • asp.net通过消息队列处理高并发请求(以抢小米手机为例)

    这篇文章主要介绍了asp.net通过消息队列处理高并发请求(以抢小米手机为例),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • 简单用VBS调用企业微信机器人发定时消息的方法

    这篇文章主要介绍了简单用VBS调用企业微信机器人发定时消息的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-12-08