C#在Linux+Mono环境中使用微信支付证书
最近特殊的需求,要把微信平臺(tái)一個(gè)功能頁(yè)面部署到Linux(CentOS6.5)下,其中涉及到微信支付退款。
鑒于之前實(shí)踐過(guò)mono+jexus+asp.net mvc的部署,于是問(wèn)題重點(diǎn)在于解決對(duì)商戶(hù)證書(shū)的調(diào)用問(wèn)題。
?
查看微信支付官方文檔關(guān)于證書(shū)的使用說(shuō)明
◆ apiclient_cert.p12是商戶(hù)證書(shū)文件,除PHP外的開(kāi)發(fā)均使用此證書(shū)文件。
◆ 商戶(hù)如果使用.NET環(huán)境開(kāi)發(fā),請(qǐng)確認(rèn)Framework版本大于2.0,必須在操作系統(tǒng)上雙擊安裝證書(shū)apiclient_cert.p12后才能被正常調(diào)用。
◆ 商戶(hù)證書(shū)調(diào)用或安裝都需要使用到密碼,該密碼的值為微信商戶(hù)號(hào)(mch_id)
◆ PHP開(kāi)發(fā)環(huán)境請(qǐng)使用商戶(hù)證書(shū)文件apiclient_cert.pem和apiclient_key.pem?,rootca.pem是CA證書(shū)。
?
1.使用mono自帶工具certmgr導(dǎo)入.p12證書(shū)
certmgr -add -c -m -p 密碼 My ApiClient_cert.p122.編寫(xiě)測(cè)試程序
using System;using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
public class TlsTest {
public static void Main(string[] args){HttpWebResponse webreponse; string strHtml = "NO";
try{ //系統(tǒng)必須已經(jīng)導(dǎo)入cert指向的證書(shū)string url =
"https://api.mch.weixin.qq.com/secapi/pay/refund";
//My即對(duì)應(yīng)”個(gè)人“存儲(chǔ)區(qū),固定不可改變X509Store store = new X509Store("My",
StoreLocation.LocalMachine);store.Open(OpenFlags.ReadOnly|OpenFlags.OpenExistingOnly);X509Certificate cer = store.Certificates.Find(
X509FindType.FindByThumbprint,
"546FCAA50DB599C5439AC8139C69393D5DB243D0", false)[0]; //遍歷證書(shū)查看Hash;windows下可直接雙擊安裝,查看屬性 ? ? ? ? ? ?//Console.WriteLine(store.Certificates.Count); ? ? ? ? ? ?//foreach(var c in store.Certificates){ ? ? ? ? ? ?// //Console.WriteLine("{0},{1},{2},{3},{4},{5}", c.GetCertHashString(), c.FriendlyName, c.GetFormat(), c.IssuerName, c.SubjectName, c.Thumbprint); ? ? ? ? ? ?// ? ?if (c.GetCertHashString() == "546FCAA50DB599C5439AC8139C69393D5DB243D0") ? ? ? ? ? ?// ? ?{ ? ? ? ? ? ?// ? ? ? ?Console.WriteLine("found"); ? ? ? ? ? ?// ? ? ? ?cer = c; ? ? ? ? ? ?// ? ? ? ?break; ? ? ? ? ? ?// ? ?} ? ? ? ? ? ?//}HttpWebRequest webrequest =
(HttpWebRequest)HttpWebRequest.Create(url);webrequest.ClientCertificates.Add(cer);webrequest.Method = "post";webrequest.KeepAlive = true;webreponse = (HttpWebResponse)webrequest.GetResponse();Stream stream = webreponse.GetResponseStream();
string resp = string.Empty;
using (StreamReader reader = new StreamReader(stream)){resp = reader.ReadToEnd();}strHtml = resp;}
catch (Exception exp){strHtml = exp.ToString();}Console.WriteLine(strHtml);} }
3.運(yùn)行測(cè)試程序
mono SSLtest.exe結(jié)果運(yùn)行報(bào)錯(cuò)
decryption has failed.) ---> System.IO.IOException:
The authentication or decryption has failed. --->
System.IO.IOException: The authentication or decryption has failed.
---> Mono.Security.Protocol.Tls.TlsException: Invalid certificate
received from server. Error code: 0xffffffff800b0109at Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecor
(IAsyncResult asyncResult) <0x40713980 + 0x0013e>
in <filename unknown>:0 at Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord
(IAsyncResult ar, Boolean ignoreEmpty) <0x407138b0 + 0x00031> in
<filename unknown>:0 at Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker
(IAsyncResult result) <0x4070d2d0 + 0x0023a>
in <filename unknown>:0 --- End of inner exception stack trace ---at Mono.Security.Protocol.Tls.SslClientStream.EndNegotiateHandshake
(IAsyncResult result) <0x40726300 + 0x000f3>
in <filename unknown>:0 at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback
(IAsyncResult asyncResult) <0x40726050 + 0x00086>
in <filename unknown>:0
--- End of inner exception stack trace ---at Mono.Security.Protocol.Tls.SslStreamBase.EndRead
(IAsyncResult asyncResult) <0x4070a990 + 0x00199>
in <filename unknown>:0 at Mono.Net.Security.Private.LegacySslStream.EndAuthenticateAsClient
(IAsyncResult asyncResult) <0x4070a8f0 + 0x00042>
in <filename unknown>:0 at Mono.Net.Security.Private.LegacySslStream.AuthenticateAsClient
(System.String targetHost,
System.Security.Cryptography.X509Certificates.
X509CertificateCollection clientCertificates,
SslProtocols enabledSslProtocols,
Boolean checkCertificateRevocation) <0x40704650 + 0x00055>
in <filename unknown>:0 at Mono.Net.Security.MonoTlsStream.CreateStream
(System.Byte[] buffer)
<0x40703e00 + 0x00145> in <filename unknown>:0 --- End of inner exception stack trace ---at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult)
<0x406fcf50 + 0x001ed> in <filename unknown>:0 at System.Net.HttpWebRequest.GetResponse () <0x406f5210 + 0x00053>
in <filename unknown>:0 at TlsTest.Main (System.String[] args) <0x406a7d80 + 0x002c6> in
<filename unknown>:0
?
4.發(fā)現(xiàn)錯(cuò)誤原因是"Invalid certificate received from server",這個(gè)問(wèn)題在Mono文檔中已有說(shuō)明:
That’s probably because you do not trust the site you are connecting to. Note that a default installation of Mono doesn’t trust anyone!
默認(rèn)情況下,任何站點(diǎn)都不被Mono信任!
同時(shí)也給出了4個(gè)解決方案:
使用cert-sync工具同步Mono和系統(tǒng)的證書(shū)存儲(chǔ)區(qū)
程序?qū)崿F(xiàn)ICertificatePolicy自行決定信任規(guī)則
使用certmgr.exe導(dǎo)入受信證書(shū)
使用mozroots.exe自動(dòng)導(dǎo)入常用的可信根證書(shū)
?
5.嘗試解決方案2
ServicePointManager.ServerCertificateValidationCallback =new RemoteCertificateValidationCallback(CheckValidationResult);
private static bool CheckValidationResult(object sender,
X509Certificate c,
X509Chain chain, SslPolicyErrors errors) {
return true; }
報(bào)錯(cuò)問(wèn)題雖然可以解決,但對(duì)所有情況均信任不是一個(gè)好的解決方法,根據(jù)X509Certificate c進(jìn)行判斷理應(yīng)可行,沒(méi)有再進(jìn)一步探索
?
6.嘗試解決方案4
使用mozroots自動(dòng)下載安裝常用的根證書(shū)
mozroots --import --sync顯示成功導(dǎo)入100+根證書(shū),重新執(zhí)行測(cè)試程序仍然報(bào)錯(cuò)。
這個(gè)結(jié)果一度使我認(rèn)為此方法無(wú)效,但偶然在本地測(cè)試卻通過(guò)了。
?
對(duì)比發(fā)現(xiàn)生效的下載路徑是:
https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
而無(wú)效的下載路徑是:
http://mxr.mozilla.org/seamonkey/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1
于是手動(dòng)下載文件并指定mozroots安裝指定的文件
wget https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
mozroots --import --sync --file certdata.txt
這時(shí),執(zhí)行測(cè)試程序運(yùn)行正常
<xml><return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[post數(shù)據(jù)為空]]></return_msg> </xml>?
7.總結(jié)
使用mozroots是解決問(wèn)題的簡(jiǎn)單方法,但由于mono版本問(wèn)題會(huì)導(dǎo)致默認(rèn)的下載文件并不有效。本地有效版本:mono 4.6.0.0,使用中已提示建議使用cert-sync [WARNING: mozroots is deprecated, please move to cert-sync instead.]
服務(wù)器版本:mono 4.4.1.0,默認(rèn)下載文件無(wú)效,這不得不說(shuō)是個(gè)坑。
原文鏈接:http://www.cnblogs.com/himax/p/how_to_use_wechat_cert_with_mono.html
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的C#在Linux+Mono环境中使用微信支付证书的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 国庆假期请假公告
- 下一篇: 微信小程序这么火,到底会对C#开发者带来