網銀的接口不難,可是開通網銀接口須要不小的費用。
相關資源彙編下載:html
最近關注項目中在線支付,因此看一下文檔,在線支付應用開發:java
基本全部的在線支付均採用如下方式:git
客戶點擊結賬時將關於訂單的信息和貨幣信息,相應的信息URL,通過md5或其餘方式發送(可能Socket和Http或Https)支付平臺(塊錢,paypal或支付寶等),支付平臺處理完畢時根據相應URL,返回相關的信息(付款信息,訂單信息,驗證信息).算法
在實際操做Money的問題人們一貫關注他的安全性等問題,同時本人習慣在經過http方式訪問非外網時採用Commons-httpclient的post發送實現,簡單方便,因此採用此種實現:具體看如下API和原代碼:apache
網銀在線支付API接口:編程
商戶>>>>>>網銀在線支付:數組
<form method=post action="https://pay.chinaebank.cn/select_bank">安全
<input type=hidden name=v_mid value="1001"> 商戶編號app
<input type=hidden name=v_oid value="19990720-1001-000001234"> 訂單編號dom
<input type=hidden name=v_amount value="13.45"> 訂單總金額
<input type=hidden name=v_moneytype value="0"> 幣種
<input type=hidden name=v_url value="http://domain/program">
支付動做完成後返回到該url,支付結果以POST方式發送
<input type=hidden name=v_md5info value="1630DC083D70A1E8AF60F49C143A7B95"> 訂單MD5校驗碼
<input type="hidden" name="remark1 " value="">備註字段1
<input type="hidden" name="remark2" value="">備註字段2
<input type=hidden name=v_rcvname value="張三"> 收貨人姓名
<input type=hidden name=v_rcvaddr value="北京海淀"> 收貨人地址
<input type=hidden name=v_rcvtel value="68475566"> 收貨人電話
<input type=hidden name=v_rcvpost value="100036"> 收貨人郵編
<input type=hidden name=v_orderstatus value="0"> 商品信息
<input type=hidden name=v_ordername value="李四"> 定貨人姓名
<input type=hidden name= v_orderemail value="test@test.com"> 定貨人郵件
<input type=submit value="網銀在線支付">
</form>
MD5校驗串生成方法:當消費者在商戶端生成最終訂單的時候,將訂單中的v_amount v_moneytype v_oid v_mid v_url key六個參數的value值拼成一個無間隔的字符串(順序不要改變)。參數key是商戶的MD5密鑰(該密匙可在登錄商戶管理界面後自行更改。)
網銀在線支付>>>商戶
支付完成後頁面轉到商戶,從網銀在線支付返回的消息格式爲:
<form method=get action="v_url" target=_self> <input type="hidden" name="v_oid" value=""> <input type="hidden" name="v_pstatus" value=""> <input type="hidden" name="v_pstring" value=""> <input type="hidden" name="v_pmode" value=""> <input type="hidden" name="v_md5str" value=""> <input type="hidden" name="v_amount" value=""> <input type="hidden" name="v_moneytype" value=""> <input type="hidden" name="remark1 " value=""> <input type="hidden" name="remark2" value=""> </form> |
該消息格式詳細解釋以下:v_url是該筆訂單提交時參數v_url 的值,即網銀返回到商戶的接口地址。
變量名稱 |
變量命名 |
返回值說明 |
|
訂單編號 |
v_oid |
商戶發送的v_oid定單編號。 |
|
支付狀態 |
v_pstatus |
20(表示支付成功) 30(表示支付失敗) |
|
支付結果信息 |
v_pstring |
支付完成 支付完成 |
|
支付方式 |
v_pmode |
支付銀行,例如工商銀行 |
|
訂單MD5校驗碼 |
v_md5str |
該參數的MD5字符串的順序爲:v_oid,v_pstatus,v_amount,v_moneytype,key MD5字符串示例: 20050320-1001-0000012342012.340key 用MD5函數加密上述字符串後獲得的值若是和v_md5str值相等即代表返回的信息沒有被纂改 |
|
訂單總金額 |
v_amount |
訂單實際支付金額 |
|
幣種 |
v_moneytype |
訂單實際支付幣種 |
|
備註字段1 |
remark1 |
|
|
備註字段2 |
remark2 |
|
表3
package cn.com.vnvtrip.china.pay.proxy;
import static cn.com.vnvtrip.china.pay.commons.ChinaPayConstants.CHINABANK_NOTIFY_URL_HTTP;
import static cn.com.vnvtrip.china.pay.commons.ChinaPayConstants.CHINABANK_PAY_HTTPS;
import static cn.com.vnvtrip.china.pay.commons.ChinaPayConstants.CHINABANK_PAY_MD5_KEY;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.codec.digest.DigestUtils;
import cn.com.vnvtrip.china.pay.commons.Env;
import cn.com.vnvtrip.china.pay.commons.HTTPClient;
/**
*
* 網銀接口服務的代理
*
* @author longgangbai
*
*/
public class ChinaPayProxy {
/**
* 在下訂單時採用的的Md5加密的信息: MD5校驗串生成方法:當消費者在商戶端生成最終訂單的時候, 將訂單中的v_amount
* v_moneytype v_oid v_mid v_url key六個參數的value值拼成一個無間隔的字符串(順序不要改變)。
* 參數key是商戶的MD5密鑰(該密匙可在登錄商戶管理界面後自行更改。)
*
* @param v_amount
* @param v_moneytype
* @param v_oid
* @param v_mid
* @param v_url
* @param key
* @return
*/
private static String getMd5Sign(String v_amount, String v_moneytype,
String v_oid, String v_mid, String v_url, String key) {
StringBuffer sb = new StringBuffer();
sb.append(v_amount);
sb.append(v_moneytype);
sb.append(v_oid);
sb.append(v_mid);
sb.append(v_url);
sb.append(key);
byte[] bytes = DigestUtils.md5(sb.toString());
String md5info = new String(bytes).toUpperCase();
return md5info;
}
/**
* 調用支付網關接口網址 銀行結賬的接口代理 (本人習慣採用Commons-httpclient實現)
* 用途:用來接受商戶發給網銀在線服務支付的訂單信息
*
* @param v_mid
* 商戶編號(非空)
* @param v_oid
* 訂單編號(非空)(格式:訂單生成日期(yyyymmdd)-商戶編號-商戶流水號)字段不可超過64位
* @param v_amount
* 訂單總金額 (非空)
* @param v_moneytype
* 貨幣類型 (非空) 0:RMB 1美圓
* @param v_url
* (非空) 支付的動做完成時返回的該url,支付結果以post方式發送
* @param v_md5info
* 訂單md5校驗碼
* @param remark1
* 備註字段1(可選字段)
* @param remark2
* 備註字段2 (可選字段)
* @param v_vmd
* yyyymmdd 備註字段2 (不可爲空字段)
* @param v_rcvname
* 收貨人姓名 (自定義非網銀必須字段)
* @param v_rcvaddr
* 收貨人地址(自定義非網銀必須字段)
* @param v_rcvtel
* 收貨人電話(自定義非網銀必須字段)
* @param v_rcpost
* 收貨人郵編(自定義非網銀必須字段)
* @param v_orderstatus
* 商品信息(自定義非網銀必須字段)
* @param v_ordername
* 定貨人姓名(自定義非網銀必須字段)
* @param v_orderemail
* 定貨人郵件(自定義非網銀必須字段)
* @return
*/
public static boolean chinaBankPayCheck(String v_mid, String v_oid,
String v_amount, String v_moneytype, String v_url, String remark1,
String remark2, String v_rcvname, String v_rcvaddr,
String v_rcvtel, String v_rcpost, String v_orderstatus,
String v_ordername, String v_orderemail) {
Properties p = Env.getEnv().getProperties();
String md5key = p.getProperty(CHINABANK_PAY_MD5_KEY);
String v_md5info = getMd5Sign(v_amount, v_moneytype, v_oid, v_mid,
v_url, md5key);
Map<String, String> paramMaps = new HashMap<String, String>();
paramMaps.put("v_mid", v_mid);
paramMaps.put("v_oid", v_oid);
paramMaps.put("v_amount", v_amount);
paramMaps.put("v_moneytype", v_moneytype);
paramMaps.put("v_url", p.getProperty(CHINABANK_NOTIFY_URL_HTTP));
paramMaps.put("v_md5info", v_md5info);
paramMaps.put("remark1", remark1);
paramMaps.put("remark2", remark2);
paramMaps.put("v_rcvname", v_rcvname);
paramMaps.put("v_rcvaddr", v_rcvaddr);
paramMaps.put("v_rcvtel", v_rcvtel);
paramMaps.put("v_rcpost", v_rcpost);
paramMaps.put("v_orderstatus", v_orderstatus);
paramMaps.put("v_ordername", v_ordername);
paramMaps.put("v_orderemail", v_orderemail);
return HTTPClient.executeHttp(CHINABANK_PAY_HTTPS, paramMaps, null);
}
/**
* result爲支付完畢接受的結果的map 校驗檢測在網銀支付數據是否被攔截的
*
* @param v_oid
* 獲取結果中的訂單編號
* @param v_pstatus
* 獲取訂單的支付狀態
* @param v_pstring
* 支付的結果
* @param v_amount
* 實際支付的金額
* @param v_moneytype
* 實際支付的幣種
* @param v_md5str
* 獲取訂單校驗的MD5驗證
* @return
*/
public static boolean checkPayOff(String v_oid, String v_pstatus,
String v_pstring, String v_amount, String v_moneytype,
String v_md5str) {
Properties p = Env.getEnv().getProperties();
String md5key = p.getProperty(CHINABANK_PAY_MD5_KEY);
String checkmd5 = getCheckMd5(v_oid, v_pstatus, v_amount, v_moneytype,
md5key);
if (checkmd5.equals(v_md5str)) {
return true;
}
return false;
}
/**
* 獲得網銀訂單付款後Md5加密檢查
*
* @param v_oid
* @param v_pstatus
* @param v_amount
* @param v_moneytype
* @param key
* @return
*/
private static String getCheckMd5(String v_oid, String v_pstatus,
String v_amount, String v_moneytype, String key) {
StringBuffer sb = new StringBuffer();
sb.append(v_oid);
sb.append(v_pstatus);
sb.append(v_amount);
sb.append(v_moneytype);
sb.append(key);
byte[] bytes = DigestUtils.md5(sb.toString());
String md5info = new String(bytes).toUpperCase();
return md5info;
}
}
來自http://topmanopensource.javaeye.com/blog/497872
2010-02-09
文章分類:Java編程
這幾天 項目須要對接建設銀行的支付和查詢功能,在支付和查詢的時候將系統連接到建行指定的頁面上,因爲這些頁面是基於互聯網的,開放的,因此須要對數據加密和數字簽名。 我來實現這個數據加密解密模塊,功能已經完成了,唉,不過讓我暈死的是,建行其實一併提供了 jar 包,已經實現了數據加密解密,校驗數字簽名的功能,只不過同事沒注意到,只發接口文檔給我,沒發 jar 包給我,害我白着急了幾天,不過工做也沒算浪費,本身實現的仍是比較放心些吧。這些頁面的跳轉沒什麼技術,主要在於數據加密和數字簽名,在連接到建行頁面以前,先將參數加密,在收到建行跳轉過來的連接參數後,取出參數裏的簽名,將簽名和原始參數進行校驗,以確認目前跳轉過來的的確是建行。頁面跳轉沒什麼好說的,我所感興趣的在於加密這些地方,以及對建行文檔的理解。
按照建行的規定,咱們發送的數據須要進行 MD5 加密,建行對返回的數據進行了數字簽名,咱們須要校驗簽名的有效性。如下是建行的兩項約定:
建行附錄 1 : MAC 算法說明
校驗,校驗算法採用標準MD5算法,不帶密鑰。該算法的詳細說明請參見RFC 1321文檔。
算法對向網上銀行系統提交的交易內容進行MAC校驗,產生128位(bit)的MAC結果。輸入爲字符串,輸出爲16進制字符表示的字符串。
結果的顯示方式的描述:
位的交易結果按4位爲一個單位進行劃分,共得到32段
進制數,如0011爲0X3,1101爲0Xd。
碼錶,造成相應的字符,如0X2爲「2」,0Xd爲「d」。
。
並按上述方法進行轉換後得到的結果:
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
建行附錄 2 :數字簽名算法說明
Html代碼
算法。商戶驗證簽名的公鑰在商戶在網銀系統開戶,獲取數字證書後,登陸到網銀系統中,經過下載公鑰交易獲取。(下載後需妥善管理並及時更新商戶公鑰,以防公私鑰不匹配形成驗籤不經過)。(目前家居銀行項目組採用靜態密鑰對,上線前生成一對,發給合做商戶。)
格式表示,而且將其按照每4位(bit)轉換爲一個16進制數的方式表示,產生16進制的字符串。家居銀行使用標準MD5withRSA算法對給商戶的響應進行簽名,產生1024位(bit)的簽名結果,而且將其按照每4位(bit)轉換爲一個16進制數的方式表示,造成16進制的字符串,長度爲256。
位的交易結果按4位爲一個單位進行劃分,共得到256段
進制數,如0011爲0X3,1101爲0Xd。
碼錶,造成相應的字符,如0X2爲「2」,0Xd爲「d」。
。
串後,從中獲取簽名(格式如上)和需簽名的原文。商戶端程序(商戶自行開發MD5withRSA簽名校驗程序)將簽名和商戶端的公鑰轉換成二進制格式,與簽名的原文一塊兒對簽名的正確性進行校驗,校驗步驟以下:
算法運算原文
、2)結果。
仔細看上面兩項約定,不管是 MD5 加密仍是 RSA 加密,都有一個基礎工做,就是將二進制數據分割,換算成 16 進制字符,還須要進行逆運算。將結果按 4 位爲一個單位進行劃分,共得到 32段, 將每段當作一個 16 進制數,如 0011 爲 0X3 , 1101 爲 0Xd 。 將這個數映射到 ASCII 碼錶,造成相應的字符,如 0X2 爲「 2 」, 0Xd 爲「 d 」。 將這些字符連成一個字符串,長度爲32 。 我先實現這個功能,代碼以下:
ByteUtil.java
Java代碼