企業付款到銀行卡 .NET 版的 ,瞭解一下?
- 是不是按照微信的文檔看不懂?
- 是不是按照微信文檔走完流程後還是存在問題?
- 是不是網上找不到.NET 代碼?
- 是不是 “解密真實姓名或銀行卡號出錯”?
(我打客服電話 95017 電話問的微信 企業付款到銀行卡API 能用吧?微信不知道哪個二貨客服跟我說不能用,然後第二天朋友打電話問客服,客服說能用!就問你屌不屌~~~)
服務器部署錯誤移駕
X509 certificate not loading private key file on server
描述
企業付款業務是基於微信支付商戶平臺的資金管理能力,爲了協助商戶方便地實現企業向銀行卡付款,針對部分有開發能力的商戶,提供通過API完成企業付款到銀行卡的功能。
首先你的微信商戶平臺需要滿足微信企業付款到銀行卡的要求 也就是什麼連續一個月要有收入什麼之類的
請求
請求地址:https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank
雙向證書:是
- 證書文檔地址
- 證書下載地址:微信商戶平臺(pay.weixin.qq.com)–>賬戶設置–>API安全–>證書下載
- 商戶證書安全:證書文件不能放在web服務器虛擬目錄,應放在有訪問權限控制的目錄中,防止被他人下載。商戶服務器要做好病毒和木馬防護工作,不被非法侵入者竊取證書文件。
- 使用商戶證書
◆ apiclient_cert.p12是商戶證書文件,除PHP外的開發均使用此證書文件(.NET 使用這個證書)。
◆ 商戶如果使用.NET環境開發,請確認Framework版本大於2.0,必須在操作系統上雙擊安裝證書apiclient_cert.p12後才能被正常調用。
◆ 商戶證書調用或安裝都需要使用到密碼,該密碼的值爲微信商戶號(mch_id)
請求參數:
MD5簽名生成
(不說了,文檔說的很清楚了)
獲取RSA加密公鑰API
- 調用獲取RSA公鑰API獲取RSA公鑰,落地成本地文件,假設存儲爲public.pem
- 確定public.pem文件的存放路徑,同時修改代碼中文件的輸入路徑,加載RSA公鑰
- 用標準的RSA加密庫對敏感信息進行加密,選擇RSA_PKCS1_OAEP_PADDING填充模式【.NET RSA 加密是沒有這個填充模式的】
- 得到進行rsa加密並轉base64之後的密文
- 將密文作爲參數傳給 銀行卡號 和 真實姓名
- 接口默認輸出PKCS#1格式的公鑰,商戶需根據自己開發的語言選擇公鑰格式 【.NET 使用 PKCS#8 】
RSA公鑰格式PKCS#1,PKCS#8互轉說明,是在Linux 系統上轉的哦
- PKCS#1 轉 PKCS#8:
- openssl rsa -RSAPublicKey_in -in -pubout
- PKCS#8 轉 PKCS#1:
- openssl rsa -pubin -in -RSAPublicKey_out
- RSA加密公鑰API文檔地址
-
- 請求證書:是 [ 證書同上 ]
- 請求參數
3、RSA加密請求成功後返回【 pub_key 是 PKCS#1 格式公鑰 】
微信默認返回 PKCS#1 格式的,.NET 需要 PKCS#8 格式的。
示例:PKCS#1 轉 PKCS#8 ,linux 輸入這段命令
openssl rsa -RSAPublicKey_in -in 獲取到的公鑰存儲爲xx.pem後的文件路徑 -pubout
【 紅框 = 獲取到的公鑰存儲爲xx.pem 文件 】
【 綠框 = 命令 】
【 黃框 = 轉換成功的 PKCS#8 】
【 pem 文件內容 】
標準RSA 加密算法
對收款方銀行卡號,收款方用戶名進行加密
這一塊的代碼是整個企業付款到銀行卡接口比較難的一點
微信文檔內告訴我們:拿着獲取到的公鑰對收款方銀行卡號,收款方用戶名 進行標準RSA加密算法加密
這個時候你從網上找一段.NET RSA 加密算法……. 是不是發現怎麼請求都不正確。反覆確認了參數及公鑰後實在找不到問題所在,
於是你打了這個電話 95017 沒錯,微信幫助中心………. 幾小時後發現他們並不能解決你的問題………
根據本人真實故事編寫
沒錯,我的問題就是【 解密真實姓名或銀行卡號出錯 】
爲什麼會報這個錯誤?
你的公鑰是微信提供的,這點沒錯。
你的參數反覆檢查也沒錯。
你得RSA 加密當時我覺得也沒錯。
那麼問題只有一個 Visual Studio 錯了!沒錯!就是它的錯,地表最強IDE 的錯。
(開玩笑的。。。。)
其實錯誤的是 RSA 加密(我是從網上淘的加密方法)。
解決方法:
你去支付寶提供的接口處下載一個支付接口,然後從支付寶接口內找 RSA 加密。
有點可恥不過問題就解決了。支付寶接口地址
微信企業付款到銀行卡,成功後會告訴你微信側受理成功
代碼
請求:企業付款到銀行卡
WxPayData ,WxPayConfig,HttpService 這些類是微信其它接口提供的demo 中提取出來的,附上地址。
微信支付開發文檔->SDK與DEMO下載
protected void payToBank()
{
//!! 證書不要放在web 目錄,使用絕對路徑放置在有權限的文件夾中
//!! pem文件不要放在web 目錄,使用絕對路徑放置在有權限的文件夾中
string url = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank";
//pem 文件爲PKCS#8 公鑰
string pempath="d:/pub.pem";
string key= System.IO.File.ReadAllText(pempath);
WxPayData inputObj = new WxPayData();
inputObj.SetValue("mch_id", WxPayConfig.MCHID);//商戶號
inputObj.SetValue("partner_trade_no", "201803122431231331");//商戶訂單號
inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//隨機字符串
//.NET 自帶的RSA 加密存在問題,使用支付寶接口內的RSA 加密通過。
inputObj.SetValue("enc_bank_no", Rsa.RSAEncrypt("銀行卡號", pempath, null, true));//收款方銀行卡號,採用標準RSA算法
inputObj.SetValue("enc_true_name", Rsa.RSAEncrypt("真實姓名", pempath, null, true));//收款方用戶名
inputObj.SetValue("bank_code", "1003");//收款方開戶行
inputObj.SetValue("amount", 100);//付款金額
inputObj.SetValue("desc", "測試付款");//付款金額
inputObj.SetValue("sign", inputObj.MakeSign().ToUpper());//簽名
string xml = inputObj.ToXml();
string response = HttpService.Post(xml, url, true, 20);//調用HTTP通信接口以提交數據到API
//將xml格式的結果轉換爲對象以返回
WxPayData result = new WxPayData();
result.FromXml(response);
}
請求:獲取RSA公鑰
private string getpublickey() {
string url = "https://fraud.mch.weixin.qq.com/risk/getpublickey";
WxPayData inputObj = new WxPayData();
inputObj.SetValue("mch_id", WxPayConfig.MCHID);//商戶號
inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//隨機字符串
inputObj.SetValue("sign_type", "MD5");
inputObj.SetValue("sign", inputObj.MakeSign().ToUpper());//簽名
string xml = inputObj.ToXml();
string response = HttpService.Post(xml, url, true, 10);//調用HTTP通信接口以提交數據到API
WxPayData result = new WxPayData();
SortedDictionary<string, object> res=result.FromXml(response);
//公鑰獲取後存儲爲 pub.pem
}
支付寶RSA類
/* 支付寶RSA
* content 加密內容
* publicKeyPem 公鑰
* charset 編碼
* keyFromFile 公鑰是否是文件
*/
public class Rsa
{
/** 默認編碼字符集 */
private static string DEFAULT_CHARSET = "UTF-8";
public static string RSAEncrypt(string content, string publicKeyPem, string charset, bool keyFromFile)
{
string sPublicKeyPEM;
if (keyFromFile)
{
sPublicKeyPEM = File.ReadAllText(publicKeyPem);
}
else
{
sPublicKeyPEM = "-----BEGIN PUBLIC KEY-----\r\n";
sPublicKeyPEM += publicKeyPem;
sPublicKeyPEM += "-----END PUBLIC KEY-----\r\n\r\n";
}
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.PersistKeyInCsp = false;
RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM);
if (string.IsNullOrEmpty(charset))
{
charset = DEFAULT_CHARSET;
}
byte[] data = Encoding.GetEncoding(charset).GetBytes(content);
int maxBlockSize = rsa.KeySize / 8 - 11; //加密塊最大長度限制
if (data.Length <= maxBlockSize)
{
byte[] cipherbytes = rsa.Encrypt(data, true);
return Convert.ToBase64String(cipherbytes);
}
MemoryStream plaiStream = new MemoryStream(data);
MemoryStream crypStream = new MemoryStream();
Byte[] buffer = new Byte[maxBlockSize];
int blockSize = plaiStream.Read(buffer, 0, maxBlockSize);
while (blockSize > 0)
{
Byte[] toEncrypt = new Byte[blockSize];
Array.Copy(buffer, 0, toEncrypt, 0, blockSize);
Byte[] cryptograph = rsa.Encrypt(toEncrypt, false);
crypStream.Write(cryptograph, 0, cryptograph.Length);
blockSize = plaiStream.Read(buffer, 0, maxBlockSize);
}
return Convert.ToBase64String(crypStream.ToArray(), Base64FormattingOptions.None);
}
}