Java Http接口加簽、驗簽操作方法
1、業(yè)務背景
最近接觸了一些電商業(yè)務,發(fā)現(xiàn)在處理電商業(yè)務接口時,比如淘寶、支付類接口,接口雙方為了確保數(shù)據(jù)參數(shù)在傳輸過程中未經(jīng)過篡改,都需要對接口數(shù)據(jù)進行加簽,然后在接口服務器端對接口參數(shù)進行驗簽,確保兩個簽名是一樣的,驗簽通過之后再進行業(yè)務邏輯處理。我們這里主要介紹一下處理思路,至于簽名算法我不做過多介紹,網(wǎng)上一大堆。
2、處理思路
雙方約定好,參數(shù)按特定順序排列,比如按首字母的順序排列,如url:http://xxx/xxx.do?a=wersd&b=sd2354&c=4&signature=XXXXXXXXXXXX(signature為傳入的簽名),等你拿到入?yún)⒑螅瑢?shù)串a(chǎn)=wersd&b=sd2354&c=4按你們約定的簽名規(guī)則,自己用md5加簽一次,然后和入?yún)⒌膕ignature值對比,以確認調(diào)用者是否合法,這就是接口簽名驗證的思路。
3、實例練習
接口雙方經(jīng)過溝通,對接口達成如下共識:
1、注意事項,主要指接口的的協(xié)議、傳入?yún)?shù)類型、簽名算法、文件格式等說明

2、下面是一個電商業(yè)務接口的真實案例,雙方約定好了接口URL、業(yè)務參數(shù)、固定參數(shù)、簽名以及返回數(shù)據(jù)格式


package com.pcmall;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class APITest {
static String TEST_URL = "待定";
static String TEST_KEY = "待定";
static String TEST_SEC = "待定";
public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException {
String result = getResult(TEST_URL, getReqParam());
System.out.print(result);
}
private static String getReqParam() throws UnsupportedEncodingException, NoSuchAlgorithmException {
TreeMap<String, String> req = new TreeMap<String, String>();
req.put("a", TEST_KEY);
req.put("f", "json");
req.put("l", "zh_CN");
req.put("m", "zhongan.repair.query");
req.put("v", "1.0");
req.put("i", "" + System.currentTimeMillis() / 1000);
req.put("params", "{\"assignNo\":\"TEST018\"}");
req.put("s", sign(req, null, TEST_SEC));
StringBuilder param = new StringBuilder();
for (Iterator<Map.Entry<String, String>> it = req.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, String> e = it.next();
param.append("&").append(e.getKey()).append("=").append(URLEncoder.encode(e.getValue(), "UTF-8"));
}
return param.toString().substring(1);
}
private static String sign(Map<String, String> paramValues, List<String> ignoreParamNames, String secret) throws NoSuchAlgorithmException, UnsupportedEncodingException {
StringBuilder sb = new StringBuilder();
List<String> paramNames = new ArrayList<String>(paramValues.size());
paramNames.addAll(paramValues.keySet());
if (ignoreParamNames != null && ignoreParamNames.size() > 0) {
for (String ignoreParamName : ignoreParamNames) {
paramNames.remove(ignoreParamName);
}
}
Collections.sort(paramNames);
sb.append(secret);
for (String paramName : paramNames) {
sb.append(paramName).append(paramValues.get(paramName));
}
sb.append(secret);
MessageDigest md = MessageDigest.getInstance("SHA-1");
return byte2hex(md.digest(sb.toString().getBytes("UTF-8")));
}
private static String byte2hex(byte[] bytes) {
StringBuilder sign = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
sign.append("0");
}
sign.append(hex.toUpperCase());
}
return sign.toString();
}
private static String getResult(String urlStr, String content) {
URL url = null;
HttpURLConnection connection = null;
try {
url = new URL(urlStr);
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
connection.setUseCaches(false);
connection.connect();
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.write(content.getBytes("UTF-8"));
out.flush();
out.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
reader.close();
return buffer.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
}
服務器端代碼如下(僅供參考):
@RequestMapping("/repairTakeOrder")
@ResponseBody
public ResponseVO repairTakeOrder(@RequestBody String jsonStr) {
logger.info("repairTakeOrder入?yún)ⅲ? + jsonStr);
ResponseVO responseVO = null;
try {
RepairOrder repairOrder = JackJsonUtil.toBean(jsonStr,
RepairOrder.class);
TreeMap<String, String> paramsMap = new TreeMap<String, String>();
paramsMap.put("gsxx01", repairOrder.getGsxx01());
paramsMap.put("orderType", repairOrder.getOrderType().toString());
paramsMap.put("serviceNo", repairOrder.getServiceNo());
paramsMap.put("vipCard", repairOrder.getVipCard());
paramsMap.put("customerName", repairOrder.getCustomerName());
paramsMap.put("customerPhone", repairOrder.getCustomerPhone());
paramsMap.put("customerTel", repairOrder.getCustomerTel());
paramsMap.put("province", repairOrder.getProvince());
paramsMap.put("city", repairOrder.getCity());
paramsMap.put("county", repairOrder.getCounty());
paramsMap.put("address", repairOrder.getAddress());
paramsMap.put("salerCode", repairOrder.getSalerCode());
paramsMap.put("salerName", repairOrder.getSalerName());
paramsMap.put("storeCode", repairOrder.getStoreCode());
paramsMap.put("storeName", repairOrder.getStoreName());
paramsMap.put("site", repairOrder.getSite());
paramsMap.put("siteDesp", repairOrder.getSiteDesp());
paramsMap.put("engineerCode", repairOrder.getEngineerCode());
paramsMap.put("engineerName", repairOrder.getEngineerName());
if (repairOrder.getServiceDate() != null) {
paramsMap.put("serviceDate",
DateUtils.formatDate(repairOrder.getServiceDate()));
}
if (repairOrder.getSalePrice() != null) {
paramsMap.put("salePrice", repairOrder.getSalePrice()
.toString());
}
paramsMap.put("profitCenter", repairOrder.getProfitCenter());
paramsMap.put("costCenter", repairOrder.getCostCenter());
paramsMap.put("gsxx02", repairOrder.getGsxx02());
paramsMap.put("returnReason", repairOrder.getReturnReason());
if (repairOrder.getOriOrder() != null) {
paramsMap.put("oriOrder", repairOrder.getOriOrder().toString());
}
if (repairOrder.getOriServiceNo() != null) {
paramsMap.put("oriServiceNo", repairOrder.getOriServiceNo());
}
// 拼接簽名原串(a=1&b=2)
String paramSrc = RequestUtils.getParamSrc(paramsMap);
logger.info("簽名原串:" + paramSrc);
//進行驗簽操作
if (SignUtils.verifymd5(paramSrc, repairOrder.getSign())) {
//處理業(yè)務邏輯
responseVO=erpServiceImpl.repairTakeOrder(repairOrder);
} else {
responseVO = new ResponseVO();
responseVO.setSuccess(false);
responseVO.setErrorMsg("驗簽失敗");
}
} catch (Exception e) {
logger.error("", e);
responseVO = new ResponseVO();
responseVO.setSuccess(false);
responseVO.setErrorMsg(StringUtils.isNotBlank(e.getMessage()) ? e.getMessage() : "后臺異常");
}
return responseVO;
}
以上這篇Java Http接口加簽、驗簽操作方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot項目實現(xiàn)日志打印SQL的常用方法(包括SQL語句和參數(shù))
有時候遇到問題需要根據(jù)我們編寫的SQL進行分析,但如果不進行一些開發(fā)或者配置的話,這些SQL是不會打印到控制臺的,它們默認是隱藏的。下面給大家介紹幾種常用的方法,感興趣的朋友跟隨小編一起看看吧2024-04-04
Java多線程之線程通信生產(chǎn)者消費者模式及等待喚醒機制代碼詳解
這篇文章主要介紹了Java多線程之線程通信生產(chǎn)者消費者模式及等待喚醒機制代碼詳解,具有一定參考價值,需要的朋友可以了解下。2017-10-10
通過jenkins發(fā)布java項目到目標主機上的詳細步驟
這篇文章主要介紹了通過jenkins發(fā)布java項目到目標主機上的詳細步驟,發(fā)布java項目的步驟很簡單,通過拉取代碼并打包,備份目標服務器上已有的要發(fā)布項目,具體內(nèi)容詳情跟隨小編一起看看吧2021-10-10
spring data簡化jpa開發(fā)_動力節(jié)點Java學院整理
這篇文章主要介紹了spring data簡化jpa開發(fā),本文主要講述 Spring Data JPA,希望能夠深入學習 Spring 和 JPA,有興趣的可以了解下2017-09-09

