zoukankan      html  css  js  c++  java
  • C# .NET 拉卡拉支付接口解析 付款码支付 条码支付

    C# .NET 拉卡拉支付接口解析 付款码支付  条码支付 被扫 反扫 刷卡支付 B扫C。

    简要:

    1.测试环境给的私钥是PKCS8。签名用。

    2.CRT证书用X509Certificate2 读取出序列号,签名时用。

    3.验证签名的公钥证书是“lkl-apigw-v1-test-.cer”

    4.如果termExtInfo对象为null,得处理下JSON字符串,尾部追加“termExtInfo:{}”,否则会报HTTP 400 BAD REQUEST 错误。或者你termExtInfo对象里传个客户端IP即可。

    5.退款查询使用交易查询接口,把退款申请号传入ornOrderId即可。

    测试环境主URL:https://test.wsmsd.cn/sit/labs/txn. 

    部分代码:

    1.读取PKCS8私钥,转为C# .NET RSACryptoServiceProvider 对象,用到了BouncyCastle.Crypto库,用nuget下载最新版本即可:

    /// <summary>
            /// PKCS8 文本转RSACryptoServiceProvider 对象
            /// </summary>
            /// <param name="privateKeyPemPkcs8"></param>
            /// <returns></returns>
            public static RSACryptoServiceProvider LoadPrivateKeyPKCS8(string privateKeyPemPkcs8)
            {
    
                try
                {
                    //PKCS8是“BEGIN PRIVATE KEY”
                    privateKeyPemPkcs8 = privateKeyPemPkcs8.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("
    ", "").Replace("
    ", "").Trim();
                    privateKeyPemPkcs8 = privateKeyPemPkcs8.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("
    ", "").Replace("
    ", "").Trim();
    
                    //pkcs8 文本先转为 .NET XML 私钥字符串
                    string privateKeyXml = RSAPrivateKeyJava2DotNet(privateKeyPemPkcs8);
    
                    RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
                    publicRsa.FromXmlString(privateKeyXml);
                    return publicRsa;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
    
            /// <summary>
            /// PKCS8 私钥文本 转 .NET XML 私钥文本
            /// </summary>
            /// <param name="privateKeyPemPkcs8"></param>
            /// <returns></returns>
            public static string RSAPrivateKeyJava2DotNet(string privateKeyPemPkcs8)
            {
                RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKeyPemPkcs8));
                return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
                Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
            }

    2.读取接入者公钥的序列号,“cert-.crt”文件:

    X509Certificate2 cert = new X509Certificate2(ofdCrt.FileName);
                        txtCertSN.Text = cert.SerialNumber;

    3.私钥签名:

    public string GetSign(string appid, string serial_no, string bodyJson)
            {
                /*
                     将分配的appId、证书序列号、时间戳、随机字符串、请求报文拼接。拼接报文一共有5行,每一行为一个参数。行尾以
    (换行符,ASCII编码值为0x0A)结束,包括最后一行。
    
    具体格式如下:
    ${appid}
    +${serialNo}
    +${timeStamp}
    +${nonceStr}
    +${body}
    
                     */
    
                string timestamp = TimeStampUtil.GetTimeStampTen().ToString();//10位和13位的都可以 
                string nonce_str = Guid.NewGuid().ToString("N").Substring(12);
    
                StringBuilder sc = new StringBuilder();
                sc.AppendFormat("{0}
    ", appid);
                sc.AppendFormat("{0}
    ", serial_no);
                sc.AppendFormat("{0}
    ", timestamp);
                sc.AppendFormat("{0}
    ", nonce_str);
                sc.AppendFormat("{0}
    ", bodyJson);
                string fnstr = sc.ToString();
    
                var rsaP = RsaUtil.LoadPrivateKey(txtPrivateKey.Text, "PKCS8");
                byte[] data = Encoding.UTF8.GetBytes(fnstr);//待签名字符串转成byte数组,UTF8
                byte[] byteSign = rsaP.SignData(data, "SHA256");//对应JAVA的RSAwithSHA256
                string sign = Convert.ToBase64String(byteSign);//签名byte数组转为BASE64字符串
    
                string schema = "LKLAPI-SHA256withRSA";
                String token = "appid="" + appid + "",serial_no="" + serial_no + "",timestamp="" + timestamp
                + "",nonce_str="" + nonce_str + "",signature="" + sign + """;
                String authorization = schema + " " + token;
                return authorization;
            }

    4.空termExtInfo处理:

     MicroPayReq req = new MicroPayReq();
                    req.mercId = txtMchNo.Text.Trim();
                    req.termNo = txtTermNo.Text.Trim();
                    req.authCode = txtAuthCode.Text.Trim();
                    req.amount = total_fee.ToString();
                    req.orderId = txtOutTradeNo.Text;
                    req.subject = "条码支付-总部";
    
                    LKL_PubReq<MicroPayReq> pub = new LKL_PubReq<MicroPayReq>();                
                    pub.reqData = req;
    
                    string bodyJson = JsonConvert.SerializeObject(pub, jsetting);
                    bodyJson = bodyJson.Substring(0, bodyJson.Length - 1);
                    //空termExtInfo处理
                    bodyJson = bodyJson + ","termExtInfo":{}}";

    5.HTTP 发送报文:

    public static string HttpPostJson(string url, string body, IDictionary<string, string> header, int timeOut, IDictionary<string, string> rspHeader)
            {
                string rst = "";
                Encoding enc1 = Encoding.UTF8;
                byte[] content = enc1.GetBytes(body);
    
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "POST";
                request.ContentType = "application/json;charset=utf-8";
                request.Timeout = timeOut * 1000;
                request.ReadWriteTimeout = timeOut * 1000;
                request.KeepAlive = false;
                request.ServicePoint.Expect100Continue = false;
                request.ContentLength = content.Length;
                //设置请求header
                foreach (var item in header)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
    
                using (Stream reqStream = request.GetRequestStream())
                {
                    reqStream.Write(content, 0, content.Length);
                }
    
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                using (Stream stream = response.GetResponseStream())
                {
                    StreamReader reader = new StreamReader(stream, enc1);
                    rst = reader.ReadToEnd();
                }
    
                //收集响应header
                if (rspHeader == null)
                {
                    rspHeader = new Dictionary<string, string>();
                }
                foreach (var item in response.Headers.AllKeys)
                {
                    rspHeader.Add(item, response.Headers[item]);
                }
    
                if (response != null)
                {
                    response.Close();
                    response = null;
                }
                if (request != null)
                {
                    request.Abort();//2018-7-31,增加
                    request = null;
                }
    
                return rst;
            }

    6.读取公钥证书,转为C# RSACryptoServiceProvider对象 ,用于验证签名。

    /// <summary>
            /// 加载公钥证书
            /// </summary>
            /// <param name="publicKeyCert">公钥证书文本内容</param>
            /// <returns></returns>
            public static RSACryptoServiceProvider LoadPublicCert(string publicKeyCert)
            {
    
                publicKeyCert = publicKeyCert.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "").Replace("
    ", "").Replace("
    ", "").Trim();
    
                byte[] bytesCerContent = Convert.FromBase64String(publicKeyCert);
                X509Certificate2 x509 = new X509Certificate2(bytesCerContent);
                RSACryptoServiceProvider rsaPub = (RSACryptoServiceProvider)x509.PublicKey.Key;
                return rsaPub;
    
            }

    7.验证签名:

    /// <summary>
            /// 验证签名
            /// </summary>
            /// <param name="rspHeader">HTTP响应头</param>
            /// <param name="rspBody">响应报文</param>
            /// <param name="pubCert">公钥证书</param>
            /// <returns></returns>
            bool ValidSign(IDictionary<string, string> rspHeader, string rspBody, string pubCert)
            {
                string appid = "";
                string serial_no = "";
                string timestamp = "";
                string nonce_str = "";
                string rspSign = "";
    
                foreach (var item in rspHeader)
                {
                    if (item.Key == "Lklapi-Appid")
                        appid = item.Value;
    
                    if (item.Key == "Lklapi-Serial")
                        serial_no = item.Value;
    
                    if (item.Key == "Lklapi-Timestamp")
                        timestamp = item.Value;
    
                    if (item.Key == "Lklapi-Nonce")
                        nonce_str = item.Value;
    
                    if (item.Key == "Lklapi-Signature")
                        rspSign = item.Value;
                }
    
                StringBuilder sc = new StringBuilder();
                sc.AppendFormat("{0}
    ", appid);
                sc.AppendFormat("{0}
    ", serial_no);
                sc.AppendFormat("{0}
    ", timestamp);
                sc.AppendFormat("{0}
    ", nonce_str);
                sc.AppendFormat("{0}
    ", rspBody);
                string fnstr = sc.ToString();
    
                byte[] byteCon = Encoding.UTF8.GetBytes(fnstr);
    
                byte[] byteRspSign = Convert.FromBase64String(rspSign);
                var rsaPub = RsaUtil.LoadPublicCert(pubCert);
    
                bool bRst = rsaPub.VerifyData(byteCon, "SHA256", byteRspSign);
    
                return bRst;
    
            }

    C# .NET 的RSA CryptoServiceProvider对象+SHA256 哈希算法,等效于JAVA的 SHA256withRSA.

    完整调用代码:https://gitee.com/runliuv/mypub/tree/master/donetproj/

  • 相关阅读:
    进度条加载
    插件
    倒计时
    阿里云oss教程
    拖拽排序插件 ---- Dragula
    预览图片代码
    Error: spawn xxxx ENOENT原因与解决
    关于环境配置的随笔
    js下载文件
    QuickStart系列:docker部署之redis
  • 原文地址:https://www.cnblogs.com/runliuv/p/15055237.html
Copyright © 2011-2022 走看看