一:背景: 目前項目使用的是php語言開發,需要接入中國工商銀行的ICBC的線上支付接口。
二:遇到的問題:支付時需要對數據簽名,但是銀行那邊不提供php版本的程序,只有java版本的,以下是對接人回復的郵件:
三:思路:
目前大概有3種解決方案:
1. 通過使用一個叫 php-java-bridge 的插件,在php中調用java的函數
2. 把java的函數改寫成php版本
3. 在服務器配置javaWeb環境,通過http請求把簽名的參數傳入,從而獲取簽名
四: 具體做法:
我採取的是第3種方法,畢竟對java不太熟悉,不想在語言層面作文章。
我使用到的是ubuntu14.04 作爲服務器,首先配置javaWeb的環境
1. 因爲php的環境已經配置好了,所以 php環境的配置環境可以參考: http://www.cnblogs.com/weishuan/p/4402744.html
2. tomcat 的環境配置:
sudo apt update
sudo apt install tomcat7//安裝tomcat7
sudo apt installdefault-jdk //javac 編譯
安裝好之後,默認的端口是8080,可以通過 http://www.服務器url:8080 驗證
如果需要修改端口號,可以修改 /var/lib/tomcat7/config/server.xml
//原來的配置
//修改後的配置
接下來就是java的代碼
getSign.java
importjava.io.File;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.IOException;importjava.io.PrintWriter;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importcn.com.infosec.icbc.ReturnValue;/*** Servlet implementation class getSign*/@WebServlet("/getSign")public class getSign extendsHttpServlet {private static final long serialVersionUID = 1L;/***@seeHttpServlet#HttpServlet()*/
publicgetSign() {super();
}protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {
doPost(request,response);
}protected void doPost(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {
PrintWriter out=response.getWriter();
String type= request.getParameter("type"); //區分是調用哪個函數if (type != null) {
String interfaceName= request.getParameter("interfaceName");
String interfaceVersion= request.getParameter("interfaceVersion");
String areaCode= request.getParameter("areaCode");
String merID= request.getParameter("merID");
String merAcct= request.getParameter("merAcct");
String merURL= request.getParameter("merURL");
String notifyType= request.getParameter("notifyType");
String orderid= request.getParameter("orderid");
String amount= request.getParameter("amount");
String curType= request.getParameter("curType");
String resultType= request.getParameter("resultType");
String orderDate= request.getParameter("orderDate");
String merCerFileKeyPath= request.getParameter("merCerFileKeyPath");
String keyPass= request.getParameter("keyPass");
StringBuilder tranData= newStringBuilder();
tranData.append(interfaceName).append(interfaceVersion).append(areaCode).append(merID).append(merAcct).append(merURL).append(notifyType).append(orderid).append(amount).append(curType).append(resultType).append(orderDate);
String MerSign=getMerSignMsgBase64(tranData.toString(), merCerFilePath, keyPass);
out.print(MerSign);
}else{
String merCerFileCrtPath= request.getParameter("merCerFileCrtPath");
String merCertBase64=getMerCertBase64(merCerFilePath);
out.print(merCertBase64);
}
}public staticString getMerSignMsgBase64(String tranData,String merCerFilePath,String keyPass) {byte[] tranByteSrc =tranData.toString().getBytes();char[] keyPasss =keyPass.toCharArray();
File merSineFile= newFile(merCerFilePath);
FileInputStream fileInputStream;try{
fileInputStream= newFileInputStream(merSineFile.getAbsolutePath());byte[] sineBytes = new byte[fileInputStream.available()];
fileInputStream.read(sineBytes);
fileInputStream.close();byte[] sign =ReturnValue.sign(tranByteSrc,tranByteSrc.length,sineBytes,keyPasss);byte[] EncSign =ReturnValue.base64enc(sign);
String merSignMsgBase64= new String(EncSign,"UTF-8").toString();
merSignMsgBase64= merSignMsgBase64.replace("\n", "");
merSignMsgBase64= merSignMsgBase64.replace("\r", "");returnmerSignMsgBase64;
}catch(Exception e) {
System.out.println("getMerSignMsgBase64"+e.getMessage());
e.printStackTrace();
}return "";
}public staticString getMerCertBase64(String merCerFilePath) {
File merCerFile= newFile(merCerFilePath);
FileInputStream fileInputStream;try{
fileInputStream= newFileInputStream(merCerFile.getAbsolutePath());
System.out.println(merCerFile.getAbsolutePath());byte[] bytes = new byte[fileInputStream.available()];
fileInputStream.read(bytes);
fileInputStream.close();byte[] EncCerts=ReturnValue.base64enc(bytes);
String merCertBase64=newString(EncCerts).toString();
merCertBase64= merCertBase64.replace("\n", "");
merCertBase64= merCertBase64.replace("\r", "");
System.out.println("IcbcOpayFileReader.getMerCertBase64:"+merCertBase64);returnmerCertBase64;
}catch(FileNotFoundException e) {
System.out.println("getMerCertBase64"+e.getMessage());
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}return "";
}
}
通過http的post或者get方法接收參數,簽名後返回字符串。
部署java的代碼,在/var/lib/tomcat7/webapps/目錄下,新建一個icbc的文件夾:
先看web.xml裏面的內容
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"metadata-complete="true">
icbc
getSign
icbc
/getSign
關於getSign.class的編譯,先確保工行的兩個jar包放在lib的目錄里,然後在getSign.java所在的路徑執行以下目錄
javac -cp /var/lib/tomcat7/webapps/icbc/WEB-INF/lib/InfosecCrypto_Java1_02_JDK13+.jar:/var/lib/tomcat7/webapps/icbc/WEB-INF/lib/icbc.jar:/usr/share/tomcat7/lib/servlet-api.jar -d /var/lib/tomcat7/webapps/icbc/WEB-INF/classes/ getSign.java
新建一個 /var/www/icbc/ 的文件,把 getSign.java 丟進去,爲了方便,我新建一個腳本文件 javac_icbc.sh
if javac -cp /var/lib/tomcat7/webapps/icbc/WEB-INF/lib/InfosecCrypto_Java1_02_JDK13+.jar:/var/lib/tomcat7/webapps/icbc/WEB-INF/lib/icbc.jar:/usr/share/tomcat7/lib/servlet-api.jar -d /var/lib/tomcat7/webapps/icbc/WEB-INF/classes/getSign.java
then
echo"javac -cp /var/lib/tomcat7/webapps/icbc/WEB-INF/lib/InfosecCrypto_Java1_02_JDK13+.jar:/var/lib/tomcat7/webapps/icbc/WEB-INF/lib/icbc.jar:/usr/share/tomcat7/lib/servlet-api.jar -d /var/lib/tomcat7/webapps/icbc/WEB-INF/classes/ getSign.java"echo"------ 编译成功,重启tomcat 服务器 --------"
if sudo /etc/init.d/tomcat7 restart
then
echo"------ 服务器重启成功 ---------"
elseecho"------ 服务器重启失败, 请手动输入下面命令重启 ------"echo"sudo /etc/init.d/tomcat7 restart"fielseecho"------ 编译失败,请查看 /var/lib/tomcat7/webapps/icbc/WEB-INF/lib/ 文件夹是否存在以下2个文件: --------"echo"1. InfosecCrypto_Java1_02_JDK13+.jar"echo"2. icbc.jar"fi
然後添加執行權限:
sudo chmod +x javac_icbc.sh
在執行文件編譯之前,請確保 /var/lib/tomcat7/webapps/icbc/ 具有讀寫權限
sudo chmod -R 777 /var/lib/tomcat7/webapps/icbc/sudo chmod-R 777 /var/lib/tomcat7/webapps/icbc/*
然後執行javac_icbc.sh
./javac_icbc.sh
最後,測試一下環境是否配置成功
確保你的公鑰和私鑰都有權限
sudo chmod -R 777 私鑰.keysudochmod -R 777 公鑰.crt
新建一個index.php文件測試一下:
$url = "http://localhost:8080/icbc/getSign?merCerFileCrtPath=".$merCerFileCrtPath;function _request($url){$ch=curl_init();
curl_setopt($ch,CURLOPT_HEADER,0);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_URL,$url);$result=curl_exec($ch);
curl_close($ch);return $result;
}echo _request($getBaseUrl);echo "
";echo "-----------";echo _request($getSignUrl);
最後能獲取簽名:
最後的最後 :
在開發過程中,我遇到了一個問題, 通過post或者get 方法時,傳遞的參數過多,超出tomcat的緩衝區,目前還沒解決。
org.apache.coyote.http11.AbstractHttp11Processor process
信息: Error parsing HTTP request header
Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
百度和google 發現是:Tomcat的header缓冲区大小不够,只需要在server.xml中增加maxHttpHeaderSize字段即可
但是我加了還是報錯,無奈只能把post的參數減少,把固定的參數寫死在java文件中。