Ping++ 支付接口对接
2017-07-29 15:14
246 查看
一、请求charge对象
[java] view plain copy print?
package com.bra.modules.util.pingplusplus;
import com.bra.common.utils.SystemPath;
import com.pingplusplus.Pingpp;
import org.springframework.stereotype.Service;
import java.io.File;
/**
* Created by Afon on 16/4/26.
*/
@Service
public class PingPlusPlusService {
/**
* Pingpp 管理平台对应的 API Key
*/
private final static String apiKey = “”;
/**
* Pingpp 管理平台对应的应用 ID
*/
private final static String appId = “”;
/**
* 你生成的私钥路径
*/
private final static String privateKeyFilePath = File.separator+SystemPath.getClassPath()+“res”+ File.separator+“rsa_private_key.pem”;
public static String charge(String orderNo,int amount,String subject,String body,String channel,String clientIP){
// 设置 API Key
Pingpp.apiKey = apiKey;
// 设置私钥路径,用于请求签名
Pingpp.privateKeyPath = privateKeyFilePath;
PingPlusCharge charge=new PingPlusCharge(appId);
String chargeString=charge.createCharge(orderNo,amount,subject,body,channel,clientIP);
return chargeString;
}
}
[java] view plain copy print?
package com.bra.modules.util.pingplusplus;
import com.pingplusplus.exception.PingppException;
import com.pingplusplus.model.Charge;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Afon on 16/4/26.
*/
public class PingPlusCharge {
private String appId;
PingPlusCharge(String appId) {
this.appId = appId;
}
public String createCharge(String orderNo, int amount, String subject, String body, String channel, String clientIP) {
/**
* 或者直接设置私钥内容
Pingpp.privateKey = ”—–BEGIN RSA PRIVATE KEY—–\n” +
”… 私钥内容字符串 …\n” +
”—–END RSA PRIVATE KEY—–\n”;
*/
Map<String, Object> chargeMap = new HashMap<String, Object>();
chargeMap.put(”amount”, amount);
chargeMap.put(”currency”, “cny”);
chargeMap.put(”subject”, subject);
chargeMap.put(”body”, body);
chargeMap.put(”order_no”, orderNo);
chargeMap.put(”channel”, channel);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, 15);//15分钟失效
long timestamp = cal.getTimeInMillis()/ 1000L;
chargeMap.put(”time_expire”, timestamp);
chargeMap.put(”client_ip”, clientIP); // 客户端 ip 地址(ipv4)
Map<String, String> app = new HashMap<String, String>();
app.put(”id”, appId);
chargeMap.put(”app”, app);
String chargeString = null;
try {
//发起交易请求
Charge charge = Charge.create(chargeMap);
// 传到客户端请先转成字符串 .toString(), 调该方法,会自动转成正确的 JSON 字符串
chargeString = charge.toString();
} catch (PingppException e) {
e.printStackTrace();
}
return chargeString;
}
}
三、webhook
[java] view plain copy print?
@RequestMapping(value = “webhooks”)
@ResponseBody
public void webhooks ( HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
/*System.out.println(“ping++ webhooks”);*/
request.setCharacterEncoding(”UTF8”);
//获取头部所有信息
Enumeration headerNames = request.getHeaderNames();
String signature=null;
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
String value = request.getHeader(key);
if(“x-pingplusplus-signature”.equals(key)){
signature=value;
}
}
/*System.out.println(“signature”+signature);*/
// 获得 http body 内容
StringBuffer eventJson=new StringBuffer();
BufferedReader reader= null;
try {
reader = request.getReader();
do{
eventJson.append(reader.readLine());
}while(reader.read()!=-1);
} catch (IOException e) {
e.printStackTrace();
}
reader.close();
JSONObject event=JSON.parseObject(eventJson.toString());
boolean verifyRS=false;
try {
PublicKey publicKey= WebhooksVerifyService.getPubKey();
/* System.out.println(publicKey);*/
verifyRS=WebhooksVerifyService.verifyData(eventJson.toString(),signature,publicKey);
} catch (Exception e) {
e.printStackTrace();
}
if(verifyRS) {
/*System.out.println(“签名验证成功”);*/
if (“charge.succeeded”.equals(event.get(“type”))) {
JSONObject data = JSON.parseObject(event.get(”data”).toString());
JSONObject object = JSON.parseObject(data.get(”object”).toString());
String orderId = (String) object.get(”order_no”);
/*System.out.println(“orderId:”+orderId);*/
String channel = (String) object.get(”channel”);
String payType = null;
int amountFen = (int) object.get(“amount”);
Double amountYuan = amountFen * 1.0 / 100;//ping++扣款,精确到分,而数据库精确到元
Double weiXinInput = null;
Double aliPayInput = null;
Double bankCardInput = null;
if (“wx”.equals(channel)) {
payType = ”4”;//支付类型(1:储值卡,2:现金,3:银行卡,4:微信,5:支付宝,6:优惠券,7:打白条;8:多方式付款;9:微信个人,10:支付宝(个人))
weiXinInput = amountYuan;
} else if (“alipay”.equals(channel)) {
payType = ”5”;
aliPayInput = amountYuan;
} else if (“upacp”.equals(channel) || “upacp_wap”.equals(channel) || “upacp_pc”.equals(channel)) {
payType = ”3”;
bankCardInput = amountYuan;
}
Double couponInput;
ReserveVenueCons order = reserveAppVenueConsService.get(orderId);
if (order != null) {
Double orderPrice = order.getShouldPrice();
couponInput = orderPrice - amountYuan;//订单金额-ping++扣款 等于优惠金额
Boolean bool = reserveAppVenueConsService.saveSettlement(order, payType, amountYuan,
0.0, bankCardInput, weiXinInput, aliPayInput, couponInput);
if (bool) {
/* System.out.println(“订单结算成功”);*/
response.setStatus(200);
//return ”订单结算成功”;
} else {
/* System.out.println(“订单结算失败”);*/
//return ”订单结算失败”;
response.setStatus(500);
}
} else {
/* System.out.println(“该订单不存在”);*/
//return ”该订单不存在”;
response.setStatus(500);
}
}
}else{
/*System.out.println(“签名验证失败”);*/
//return ”签名验证失败”;
response.setStatus(500);
}
}
[java] view plain copy print?
package com.bra.modules.util.pingplusplus;
import com.bra.common.utils.SystemPath;
import org.apache.commons.codec.binary.Base64;
import java.io.*;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
/**
* Created by sunkai on 15/5/19. webhooks 验证签名示例
*
* 该实例演示如何对 Ping++ webhooks 通知进行验证。
* 验证是为了让开发者确认该通知来自 Ping++ ,防止恶意伪造通知。用户如果有别的验证机制,可以不进行验证签名。
*
* 验证签名需要 签名、公钥、验证信息,该实例采用文件存储方式进行演示。
* 实际项目中,需要用户从异步通知的 HTTP header 中读取签名,从 HTTP body 中读取验证信息。公钥的存储方式也需要用户自行设定。
*
* 该实例仅供演示如何验证签名,请务必不要直接 copy 到实际项目中使用。
*
*/
public class WebhooksVerifyService {
private static String pubKeyPath = File.separator+ SystemPath.getClassPath()+“res”+ File.separator+“pingpp_public_key.pem”;
private static String eventPath = File.separator+SystemPath.getClassPath()+“res”+ File.separator+“webhooks_raw_post_data.json”;
private static String signPath = File.separator+SystemPath.getClassPath()+“res”+ File.separator+“signature.txt”;
/**
* 验证 webhooks 签名,仅供参考
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
runDemos();
}
public static void runDemos() throws Exception {
// 该数据请从 request 中获取原始 POST 请求数据, 以下仅作为示例
String webhooksRawPostData = getStringFromFile(eventPath);
System.out.println(”——- POST 原始数据 ——-“);
System.out.println(webhooksRawPostData);
// 签名数据请从 request 的 header 中获取, key 为 X-Pingplusplus-Signature (请忽略大小写, 建议自己做格式化)
String signature = getStringFromFile(signPath);
System.out.println(”——- 签名 ——-“);
System.out.println(signature);
boolean result = verifyData(webhooksRawPostData, signature, getPubKey());
System.out.println(”验签结果:” + (result ? “通过” : “失败”));
}
/**
* 读取文件, 部署 web 程序的时候, 签名和验签内容需要从 request 中获得
* @param filePath
* @return
* @throws Exception
*/
public static String getStringFromFile(String filePath) throws Exception {
FileInputStream in = new FileInputStream(filePath);
InputStreamReader inReader = new InputStreamReader(in, “UTF-8”);
BufferedReader bf = new BufferedReader(inReader);
StringBuilder sb = new StringBuilder();
String line;
do {
line = bf.readLine();
if (line != null) {
if (sb.length() != 0) {
sb.append(”\n”);
}
sb.append(line);
}
} while (line != null);
return sb.toString();
}
/**
* 获得公钥
* @return
* @throws Exception
*/
public static PublicKey getPubKey() throws Exception {
String pubKeyString = getStringFromFile(pubKeyPath);
pubKeyString = pubKeyString.replaceAll(”(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)”, “”);
byte[] keyBytes = Base64.decodeBase64(pubKeyString);
// generate public key
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(”RSA”);
PublicKey publicKey = keyFactory.generatePublic(spec);
return publicKey;
}
/**
* 验证签名
* @param dataString
* @param signatureString
* @param publicKey
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws SignatureException
*/
public static boolean verifyData(String dataString, String signatureString, PublicKey publicKey)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
byte[] signatureBytes = Base64.decodeBase64(signatureString);
Signature signature = Signature.getInstance(”SHA256withRSA”);
signature.initVerify(publicKey);
signature.update(dataString.getBytes(”UTF-8”));
return signature.verify(signatureBytes);
}
}
[java] view plain copy print?
package com.bra.modules.util.pingplusplus;
import com.bra.common.utils.SystemPath;
import com.pingplusplus.Pingpp;
import org.springframework.stereotype.Service;
import java.io.File;
/**
* Created by Afon on 16/4/26.
*/
@Service
public class PingPlusPlusService {
/**
* Pingpp 管理平台对应的 API Key
*/
private final static String apiKey = “”;
/**
* Pingpp 管理平台对应的应用 ID
*/
private final static String appId = “”;
/**
* 你生成的私钥路径
*/
private final static String privateKeyFilePath = File.separator+SystemPath.getClassPath()+“res”+ File.separator+“rsa_private_key.pem”;
public static String charge(String orderNo,int amount,String subject,String body,String channel,String clientIP){
// 设置 API Key
Pingpp.apiKey = apiKey;
// 设置私钥路径,用于请求签名
Pingpp.privateKeyPath = privateKeyFilePath;
PingPlusCharge charge=new PingPlusCharge(appId);
String chargeString=charge.createCharge(orderNo,amount,subject,body,channel,clientIP);
return chargeString;
}
}
package com.bra.modules.util.pingplusplus; import com.bra.common.utils.SystemPath; import com.pingplusplus.Pingpp; import org.springframework.stereotype.Service; import java.io.File; /** * Created by Afon on 16/4/26. */ @Service public class PingPlusPlusService { /** * Pingpp 管理平台对应的 API Key */ private final static String apiKey = ""; /** * Pingpp 管理平台对应的应用 ID */ private final static String appId = ""; /** * 你生成的私钥路径 */ private final static String privateKeyFilePath = File.separator+SystemPath.getClassPath()+"res"+ File.separator+"rsa_private_key.pem"; public static String charge(String orderNo,int amount,String subject,String body,String channel,String clientIP){ // 设置 API Key Pingpp.apiKey = apiKey; // 设置私钥路径,用于请求签名 Pingpp.privateKeyPath = privateKeyFilePath; PingPlusCharge charge=new PingPlusCharge(appId); String chargeString=charge.createCharge(orderNo,amount,subject,body,channel,clientIP); return chargeString; } }二、生成charge 对象
[java] view plain copy print?
package com.bra.modules.util.pingplusplus;
import com.pingplusplus.exception.PingppException;
import com.pingplusplus.model.Charge;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Afon on 16/4/26.
*/
public class PingPlusCharge {
private String appId;
PingPlusCharge(String appId) {
this.appId = appId;
}
public String createCharge(String orderNo, int amount, String subject, String body, String channel, String clientIP) {
/**
* 或者直接设置私钥内容
Pingpp.privateKey = ”—–BEGIN RSA PRIVATE KEY—–\n” +
”… 私钥内容字符串 …\n” +
”—–END RSA PRIVATE KEY—–\n”;
*/
Map<String, Object> chargeMap = new HashMap<String, Object>();
chargeMap.put(”amount”, amount);
chargeMap.put(”currency”, “cny”);
chargeMap.put(”subject”, subject);
chargeMap.put(”body”, body);
chargeMap.put(”order_no”, orderNo);
chargeMap.put(”channel”, channel);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, 15);//15分钟失效
long timestamp = cal.getTimeInMillis()/ 1000L;
chargeMap.put(”time_expire”, timestamp);
chargeMap.put(”client_ip”, clientIP); // 客户端 ip 地址(ipv4)
Map<String, String> app = new HashMap<String, String>();
app.put(”id”, appId);
chargeMap.put(”app”, app);
String chargeString = null;
try {
//发起交易请求
Charge charge = Charge.create(chargeMap);
// 传到客户端请先转成字符串 .toString(), 调该方法,会自动转成正确的 JSON 字符串
chargeString = charge.toString();
} catch (PingppException e) {
e.printStackTrace();
}
return chargeString;
}
}
package com.bra.modules.util.pingplusplus; import com.pingplusplus.exception.PingppException; import com.pingplusplus.model.Charge; import java.util.Calendar; import java.util.HashMap; import java.util.Map; /** * Created by Afon on 16/4/26. */ public class PingPlusCharge { private String appId; PingPlusCharge(String appId) { this.appId = appId; } public String createCharge(String orderNo, int amount, String subject, String body, String channel, String clientIP) { /** * 或者直接设置私钥内容 Pingpp.privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" + "... 私钥内容字符串 ...\n" + "-----END RSA PRIVATE KEY-----\n"; */ Map<String, Object> chargeMap = new HashMap<String, Object>(); chargeMap.put("amount", amount); chargeMap.put("currency", "cny"); chargeMap.put("subject", subject); chargeMap.put("body", body); chargeMap.put("order_no", orderNo); chargeMap.put("channel", channel); Calendar cal = Calendar.getInstance(); cal.add(Calendar.MINUTE, 15);//15分钟失效 long timestamp = cal.getTimeInMillis()/ 1000L; chargeMap.put("time_expire", timestamp); chargeMap.put("client_ip", clientIP); // 客户端 ip 地址(ipv4) Map<String, String> app = new HashMap<String, String>(); app.put("id", appId); chargeMap.put("app", app); String chargeString = null; try { //发起交易请求 Charge charge = Charge.create(chargeMap); // 传到客户端请先转成字符串 .toString(), 调该方法,会自动转成正确的 JSON 字符串 chargeString = charge.toString(); } catch (PingppException e) { e.printStackTrace(); } return chargeString; } }
三、webhook
[java] view plain copy print?
@RequestMapping(value = “webhooks”)
@ResponseBody
public void webhooks ( HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
/*System.out.println(“ping++ webhooks”);*/
request.setCharacterEncoding(”UTF8”);
//获取头部所有信息
Enumeration headerNames = request.getHeaderNames();
String signature=null;
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
String value = request.getHeader(key);
if(“x-pingplusplus-signature”.equals(key)){
signature=value;
}
}
/*System.out.println(“signature”+signature);*/
// 获得 http body 内容
StringBuffer eventJson=new StringBuffer();
BufferedReader reader= null;
try {
reader = request.getReader();
do{
eventJson.append(reader.readLine());
}while(reader.read()!=-1);
} catch (IOException e) {
e.printStackTrace();
}
reader.close();
JSONObject event=JSON.parseObject(eventJson.toString());
boolean verifyRS=false;
try {
PublicKey publicKey= WebhooksVerifyService.getPubKey();
/* System.out.println(publicKey);*/
verifyRS=WebhooksVerifyService.verifyData(eventJson.toString(),signature,publicKey);
} catch (Exception e) {
e.printStackTrace();
}
if(verifyRS) {
/*System.out.println(“签名验证成功”);*/
if (“charge.succeeded”.equals(event.get(“type”))) {
JSONObject data = JSON.parseObject(event.get(”data”).toString());
JSONObject object = JSON.parseObject(data.get(”object”).toString());
String orderId = (String) object.get(”order_no”);
/*System.out.println(“orderId:”+orderId);*/
String channel = (String) object.get(”channel”);
String payType = null;
int amountFen = (int) object.get(“amount”);
Double amountYuan = amountFen * 1.0 / 100;//ping++扣款,精确到分,而数据库精确到元
Double weiXinInput = null;
Double aliPayInput = null;
Double bankCardInput = null;
if (“wx”.equals(channel)) {
payType = ”4”;//支付类型(1:储值卡,2:现金,3:银行卡,4:微信,5:支付宝,6:优惠券,7:打白条;8:多方式付款;9:微信个人,10:支付宝(个人))
weiXinInput = amountYuan;
} else if (“alipay”.equals(channel)) {
payType = ”5”;
aliPayInput = amountYuan;
} else if (“upacp”.equals(channel) || “upacp_wap”.equals(channel) || “upacp_pc”.equals(channel)) {
payType = ”3”;
bankCardInput = amountYuan;
}
Double couponInput;
ReserveVenueCons order = reserveAppVenueConsService.get(orderId);
if (order != null) {
Double orderPrice = order.getShouldPrice();
couponInput = orderPrice - amountYuan;//订单金额-ping++扣款 等于优惠金额
Boolean bool = reserveAppVenueConsService.saveSettlement(order, payType, amountYuan,
0.0, bankCardInput, weiXinInput, aliPayInput, couponInput);
if (bool) {
/* System.out.println(“订单结算成功”);*/
response.setStatus(200);
//return ”订单结算成功”;
} else {
/* System.out.println(“订单结算失败”);*/
//return ”订单结算失败”;
response.setStatus(500);
}
} else {
/* System.out.println(“该订单不存在”);*/
//return ”该订单不存在”;
response.setStatus(500);
}
}
}else{
/*System.out.println(“签名验证失败”);*/
//return ”签名验证失败”;
response.setStatus(500);
}
}
@RequestMapping(value = "webhooks") @ResponseBody public void webhooks ( HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { /*System.out.println("ping++ webhooks");*/ request.setCharacterEncoding("UTF8"); //获取头部所有信息 Enumeration headerNames = request.getHeaderNames(); String signature=null; while (headerNames.hasMoreElements()) { String key = (String) headerNames.nextElement(); String value = request.getHeader(key); if("x-pingplusplus-signature".equals(key)){ signature=value; } } /*System.out.println("signature"+signature);*/ // 获得 http body 内容 StringBuffer eventJson=new StringBuffer(); BufferedReader reader= null; try { reader = request.getReader(); do{ eventJson.append(reader.readLine()); }while(reader.read()!=-1); } catch (IOException e) { e.printStackTrace(); } reader.close(); JSONObject event=JSON.parseObject(eventJson.toString()); boolean verifyRS=false; try { PublicKey publicKey= WebhooksVerifyService.getPubKey(); /* System.out.println(publicKey);*/ verifyRS=WebhooksVerifyService.verifyData(eventJson.toString(),signature,publicKey); } catch (Exception e) { e.printStackTrace(); } if(verifyRS) { /*System.out.println("签名验证成功");*/ if ("charge.succeeded".equals(event.get("type"))) { JSONObject data = JSON.parseObject(event.get("data").toString()); JSONObject object = JSON.parseObject(data.get("object").toString()); String orderId = (String) object.get("order_no"); /*System.out.println("orderId:"+orderId);*/ String channel = (String) object.get("channel"); String payType = null; int amountFen = (int) object.get("amount"); Double amountYuan = amountFen * 1.0 / 100;//ping++扣款,精确到分,而数据库精确到元 Double weiXinInput = null; Double aliPayInput = null; Double bankCardInput = null; if ("wx".equals(channel)) { payType = "4";//支付类型(1:储值卡,2:现金,3:银行卡,4:微信,5:支付宝,6:优惠券,7:打白条;8:多方式付款;9:微信个人,10:支付宝(个人)) weiXinInput = amountYuan; } else if ("alipay".equals(channel)) { payType = "5"; aliPayInput = amountYuan; } else if ("upacp".equals(channel) || "upacp_wap".equals(channel) || "upacp_pc".equals(channel)) { payType = "3"; bankCardInput = amountYuan; } Double couponInput; ReserveVenueCons order = reserveAppVenueConsService.get(orderId); if (order != null) { Double orderPrice = order.getShouldPrice(); couponInput = orderPrice - amountYuan;//订单金额-ping++扣款 等于优惠金额 Boolean bool = reserveAppVenueConsService.saveSettlement(order, payType, amountYuan, 0.0, bankCardInput, weiXinInput, aliPayInput, couponInput); if (bool) { /* System.out.println("订单结算成功");*/ response.setStatus(200); //return "订单结算成功"; } else { /* System.out.println("订单结算失败");*/ //return "订单结算失败"; response.setStatus(500); } } else { /* System.out.println("该订单不存在");*/ //return "该订单不存在"; response.setStatus(500); } } }else{ /*System.out.println("签名验证失败");*/ //return "签名验证失败"; response.setStatus(500); } }四、WebhooksVerifyService
[java] view plain copy print?
package com.bra.modules.util.pingplusplus;
import com.bra.common.utils.SystemPath;
import org.apache.commons.codec.binary.Base64;
import java.io.*;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
/**
* Created by sunkai on 15/5/19. webhooks 验证签名示例
*
* 该实例演示如何对 Ping++ webhooks 通知进行验证。
* 验证是为了让开发者确认该通知来自 Ping++ ,防止恶意伪造通知。用户如果有别的验证机制,可以不进行验证签名。
*
* 验证签名需要 签名、公钥、验证信息,该实例采用文件存储方式进行演示。
* 实际项目中,需要用户从异步通知的 HTTP header 中读取签名,从 HTTP body 中读取验证信息。公钥的存储方式也需要用户自行设定。
*
* 该实例仅供演示如何验证签名,请务必不要直接 copy 到实际项目中使用。
*
*/
public class WebhooksVerifyService {
private static String pubKeyPath = File.separator+ SystemPath.getClassPath()+“res”+ File.separator+“pingpp_public_key.pem”;
private static String eventPath = File.separator+SystemPath.getClassPath()+“res”+ File.separator+“webhooks_raw_post_data.json”;
private static String signPath = File.separator+SystemPath.getClassPath()+“res”+ File.separator+“signature.txt”;
/**
* 验证 webhooks 签名,仅供参考
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
runDemos();
}
public static void runDemos() throws Exception {
// 该数据请从 request 中获取原始 POST 请求数据, 以下仅作为示例
String webhooksRawPostData = getStringFromFile(eventPath);
System.out.println(”——- POST 原始数据 ——-“);
System.out.println(webhooksRawPostData);
// 签名数据请从 request 的 header 中获取, key 为 X-Pingplusplus-Signature (请忽略大小写, 建议自己做格式化)
String signature = getStringFromFile(signPath);
System.out.println(”——- 签名 ——-“);
System.out.println(signature);
boolean result = verifyData(webhooksRawPostData, signature, getPubKey());
System.out.println(”验签结果:” + (result ? “通过” : “失败”));
}
/**
* 读取文件, 部署 web 程序的时候, 签名和验签内容需要从 request 中获得
* @param filePath
* @return
* @throws Exception
*/
public static String getStringFromFile(String filePath) throws Exception {
FileInputStream in = new FileInputStream(filePath);
InputStreamReader inReader = new InputStreamReader(in, “UTF-8”);
BufferedReader bf = new BufferedReader(inReader);
StringBuilder sb = new StringBuilder();
String line;
do {
line = bf.readLine();
if (line != null) {
if (sb.length() != 0) {
sb.append(”\n”);
}
sb.append(line);
}
} while (line != null);
return sb.toString();
}
/**
* 获得公钥
* @return
* @throws Exception
*/
public static PublicKey getPubKey() throws Exception {
String pubKeyString = getStringFromFile(pubKeyPath);
pubKeyString = pubKeyString.replaceAll(”(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)”, “”);
byte[] keyBytes = Base64.decodeBase64(pubKeyString);
// generate public key
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(”RSA”);
PublicKey publicKey = keyFactory.generatePublic(spec);
return publicKey;
}
/**
* 验证签名
* @param dataString
* @param signatureString
* @param publicKey
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws SignatureException
*/
public static boolean verifyData(String dataString, String signatureString, PublicKey publicKey)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
byte[] signatureBytes = Base64.decodeBase64(signatureString);
Signature signature = Signature.getInstance(”SHA256withRSA”);
signature.initVerify(publicKey);
signature.update(dataString.getBytes(”UTF-8”));
return signature.verify(signatureBytes);
}
}
package com.bra.modules.util.pingplusplus; import com.bra.common.utils.SystemPath; import org.apache.commons.codec.binary.Base64; import java.io.*; import java.security.*; import java.security.spec.X509EncodedKeySpec; /** * Created by sunkai on 15/5/19. webhooks 验证签名示例 * * 该实例演示如何对 Ping++ webhooks 通知进行验证。 * 验证是为了让开发者确认该通知来自 Ping++ ,防止恶意伪造通知。用户如果有别的验证机制,可以不进行验证签名。 * * 验证签名需要 签名、公钥、验证信息,该实例采用文件存储方式进行演示。 * 实际项目中,需要用户从异步通知的 HTTP header 中读取签名,从 HTTP body 中读取验证信息。公钥的存储方式也需要用户自行设定。 * * 该实例仅供演示如何验证签名,请务必不要直接 copy 到实际项目中使用。 * */ public class WebhooksVerifyService { private static String pubKeyPath = File.separator+ SystemPath.getClassPath()+"res"+ File.separator+"pingpp_public_key.pem"; private static String eventPath = File.separator+SystemPath.getClassPath()+"res"+ File.separator+"webhooks_raw_post_data.json"; private static String signPath = File.separator+SystemPath.getClassPath()+"res"+ File.separator+"signature.txt"; /** * 验证 webhooks 签名,仅供参考 * @param args * @throws Exception */ public static void main(String[] args) throws Exception { runDemos(); } public static void runDemos() throws Exception { // 该数据请从 request 中获取原始 POST 请求数据, 以下仅作为示例 String webhooksRawPostData = getStringFromFile(eventPath); System.out.println("------- POST 原始数据 -------"); System.out.println(webhooksRawPostData); // 签名数据请从 request 的 header 中获取, key 为 X-Pingplusplus-Signature (请忽略大小写, 建议自己做格式化) String signature = getStringFromFile(signPath); System.out.println("------- 签名 -------"); System.out.println(signature); boolean result = verifyData(webhooksRawPostData, signature, getPubKey()); System.out.println("验签结果:" + (result ? "通过" : "失败")); } /** * 读取文件, 部署 web 程序的时候, 签名和验签内容需要从 request 中获得 * @param filePath * @return * @throws Exception */ public static String getStringFromFile(String filePath) throws Exception { FileInputStream in = new FileInputStream(filePath); InputStreamReader inReader = new InputStreamReader(in, "UTF-8"); BufferedReader bf = new BufferedReader(inReader); StringBuilder sb = new StringBuilder(); String line; do { line = bf.readLine(); if (line != null) { if (sb.length() != 0) { sb.append("\n"); } sb.append(line); } } while (line != null); return sb.toString(); } /** * 获得公钥 * @return * @throws Exception */ public static PublicKey getPubKey() throws Exception { String pubKeyString = getStringFromFile(pubKeyPath); pubKeyString = pubKeyString.replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", ""); byte[] keyBytes = Base64.decodeBase64(pubKeyString); // generate public key X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(spec); return publicKey; } /** * 验证签名 * @param dataString * @param signatureString * @param publicKey * @return * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws SignatureException */ public static boolean verifyData(String dataString, String signatureString, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException { byte[] signatureBytes = Base64.decodeBase64(signatureString); Signature signature = Signature.getInstance("SHA256withRSA"); signature.initVerify(publicKey); signature.update(dataString.getBytes("UTF-8")); return signature.verify(signatureBytes); } }
相关文章推荐
- Ping++ 支付接口对接
- Ping++ 支付接口对接
- ping++支付接口对接(基于SSH框架)
- 对接银联支付接口详解java版mac开发
- 支付宝”电脑网站支付“接口对接
- 支付宝支付接口对接的总结
- 第三方支付接口对接基本流程
- 对接【支付宝】支付接口
- 对接支付宝支付接口
- 第三方支付平台现号,第三方支付平台接口,第三方支付平台技术对接
- 境外支付宝接口对接--支付接口
- C#微信公众号支付接口对接
- 新浪支付接口对接的总结
- 新浪支付接口对接的总结
- 对接支付宝支付接口开发详细步骤
- Paypal REST API Java 版 PC端商城支付接口对接。
- JEECG支付服务窗专题 - 平台与服务窗接口对接
- 如何高效开发支付接口对接
- 移动应用支付接口——ping++
- ping++ 支持一站式支付接口