cybersource支付对接
开始对接之旅
在对接过程中走了很多弯路,官方给出的看着一知半解,主要是都是英文翻译的文档,本次我来分享下Secure Acceptance自动集成的支付方式。
这里准备了一份html的官方文档和pdf的版本
pdf文档
html文档
请按照文档进行商户账号注册和支付方式设置这里不多说了上图看看
商户配置
Profile ID 和 秘钥是支付的关键
下单代码
//传参请根据自己的业务逻辑进行修改
private Map<String,String> initPayGlocashInfoRefVo(PayMerchantAccountVo shroffAccountInfo, IntfPayRefVo intfPayRefVo,JsonNode jsonNode) throws Exception {
Map<String,String> data = new HashMap<>(20);
data.put("access_key", shroffAccountInfo.getPassword());//上面提到的秘钥
data.put("profile_id", shroffAccountInfo.getPayMerchantId());//Profile ID 支付认证
data.put("transaction_uuid", String.valueOf(UUID.randomUUID()));
data.put("signed_date_time", CybersourceUtil.getUTCDateTime());
data.put("locale", jsonNode.get("locale").textValue());
data.put("transaction_type", jsonNode.get("transaction_type").textValue());
data.put("reference_number", intfPayRefVo.getPayTransactionsId());
BigDecimal amount = BigDecimal.valueOf(Double.parseDouble(intfPayRefVo.getOrderAmt())/100);
data.put("amount", String.valueOf(amount));
data.put("currency", jsonNode.get("currency").textValue());
data.put("bill_to_email", intfPayRefVo.getMemberEmail());
//开关账单信息自动填写 这个是必填信息这里我不想填后台默认填写了地址
boolean isBill = jsonNode.get("isBill").asBoolean();
if (isBill){
data.put("bill_to_address_line1","1 My Apartment");
data.put("bill_to_address_city","Mountain View");
data.put("bill_to_address_state", "CA");
data.put("bill_to_address_country", "US");
data.put("bill_to_address_postal_code","94043");
}
data.put("unsigned_field_names", "");
data.put("signed_field_names", CybersourceUtil.buildDataToString(data));
String sign = null;
sign = CybersourceUtil.sign(data,shroffAccountInfo.getSign());
data.put("signature", sign);
log.info("cybersource transaction create data:{}",JsonUtils.writeValueAsString(data));
return data;
}
由后台处理的下单信息进行加密传递给前段由前段进行表单提交
<form id="payment_confirmation" action="https://testsecureacceptance.cybersource.com/oneclick/pay" method="post"/>
这个是测试支付提交 生产替换一下
https://secureacceptance.cybersource.com/oneclick/pay
CybersourceUtil 加密工具类(这个是dome 里面js 提取出来的)
public class CybersourceUtil {
//这个是支付秘钥的私钥 和加密方式
private static final String HMAC_SHA256 = "HmacSHA256";
private static final String SECRET_KEY = "9588e91d3823423d85b9b07d790990b5e95c89fac9be4592ae45bffbc2de31bd44fd649b3e874fe7abe39c8b7465323de40d2f6521b641968cf20cad39d3232263fad416ffe945e2a36466c9b6347664c0eb9e9a055748cc9d2bb0630768a53f350dc38ea322421e8d9aedefb8374df8d849dea9cdff4ae08d3e57fc07ddfdb5";
public static String sign(Map<String,String> params,String SECRET_KEY) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
return sign(buildDataToSign(params), SECRET_KEY);
}
public static String sign(String data, String secretKey) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), HMAC_SHA256);
Mac mac = Mac.getInstance(HMAC_SHA256);
mac.init(secretKeySpec);
byte[] rawHmac = mac.doFinal(data.getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(rawHmac).replace("\n", "");
}
private static String buildDataToSign(Map<String,String> params) {
String[] signedFieldNames = String.valueOf(params.get("signed_field_names")).split(",");
ArrayList<String> dataToSign = new ArrayList<String>();
for (String signedFieldName : signedFieldNames) {
dataToSign.add(signedFieldName + "=" + String.valueOf(params.get(signedFieldName)));
}
return commaSeparate(dataToSign);
}
public static String buildDataToString(Map<String,String> params) {
StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry<String, String> key : params.entrySet()) {
stringBuilder.append(key.getKey()+",");
}
stringBuilder.append("signed_field_names");
String str = stringBuilder.toString();
return str;
}
private static String commaSeparate(ArrayList<String> dataToSign) {
StringBuilder csv = new StringBuilder();
for (Iterator<String> it = dataToSign.iterator(); it.hasNext(); ) {
csv.append(it.next());
if (it.hasNext()) {
csv.append(",");
}
}
return csv.toString();
}
public static String getUTCDateTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(new Date());
}
}
支付页面展示
当然,回调地址可以定义自己的页面,也可以托管平台的页面。好了大概流程就结束了。
有的不太清楚回调是在哪里配置的 我在这里补上
https://webhook.site/#/ 方便测试回调 这里回调地址可以访问这个网址生成的虚拟站点地址 配置到商户通知URL 方便查看回调参数如下 访问地址会看到请求信息
有什么问题可以留言我会及时回复一起交流