Java Http接口加簽、驗(yàn)簽操作方法
1、業(yè)務(wù)背景
最近接觸了一些電商業(yè)務(wù),發(fā)現(xiàn)在處理電商業(yè)務(wù)接口時,比如淘寶、支付類接口,接口雙方為了確保數(shù)據(jù)參數(shù)在傳輸過程中未經(jīng)過篡改,都需要對接口數(shù)據(jù)進(jìn)行加簽,然后在接口服務(wù)器端對接口參數(shù)進(jìn)行驗(yàn)簽,確保兩個簽名是一樣的,驗(yàn)簽通過之后再進(jìn)行業(yè)務(wù)邏輯處理。我們這里主要介紹一下處理思路,至于簽名算法我不做過多介紹,網(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值對比,以確認(rèn)調(diào)用者是否合法,這就是接口簽名驗(yàn)證的思路。
3、實(shí)例練習(xí)
接口雙方經(jīng)過溝通,對接口達(dá)成如下共識:
1、注意事項(xiàng),主要指接口的的協(xié)議、傳入?yún)?shù)類型、簽名算法、文件格式等說明
2、下面是一個電商業(yè)務(wù)接口的真實(shí)案例,雙方約定好了接口URL、業(yè)務(wù)參數(shù)、固定參數(shù)、簽名以及返回?cái)?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; } }
服務(wù)器端代碼如下(僅供參考):
@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); //進(jìn)行驗(yàn)簽操作 if (SignUtils.verifymd5(paramSrc, repairOrder.getSign())) { //處理業(yè)務(wù)邏輯 responseVO=erpServiceImpl.repairTakeOrder(repairOrder); } else { responseVO = new ResponseVO(); responseVO.setSuccess(false); responseVO.setErrorMsg("驗(yàn)簽失敗"); } } catch (Exception e) { logger.error("", e); responseVO = new ResponseVO(); responseVO.setSuccess(false); responseVO.setErrorMsg(StringUtils.isNotBlank(e.getMessage()) ? e.getMessage() : "后臺異常"); } return responseVO; }
以上這篇Java Http接口加簽、驗(yàn)簽操作方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot項(xiàng)目實(shí)現(xiàn)日志打印SQL的常用方法(包括SQL語句和參數(shù))
有時候遇到問題需要根據(jù)我們編寫的SQL進(jìn)行分析,但如果不進(jìn)行一些開發(fā)或者配置的話,這些SQL是不會打印到控制臺的,它們默認(rèn)是隱藏的。下面給大家介紹幾種常用的方法,感興趣的朋友跟隨小編一起看看吧2024-04-04Java多線程之線程通信生產(chǎn)者消費(fèi)者模式及等待喚醒機(jī)制代碼詳解
這篇文章主要介紹了Java多線程之線程通信生產(chǎn)者消費(fèi)者模式及等待喚醒機(jī)制代碼詳解,具有一定參考價(jià)值,需要的朋友可以了解下。2017-10-10通過web控制當(dāng)前的SpringBoot程序重新啟動
本文主要給大家介紹了如何通過web控制當(dāng)前的SpringBoot程序重新啟動,文章給出了詳細(xì)的代碼示例供大家參考,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-11-11通過jenkins發(fā)布java項(xiàng)目到目標(biāo)主機(jī)上的詳細(xì)步驟
這篇文章主要介紹了通過jenkins發(fā)布java項(xiàng)目到目標(biāo)主機(jī)上的詳細(xì)步驟,發(fā)布java項(xiàng)目的步驟很簡單,通過拉取代碼并打包,備份目標(biāo)服務(wù)器上已有的要發(fā)布項(xiàng)目,具體內(nèi)容詳情跟隨小編一起看看吧2021-10-10spring boot 學(xué)習(xí)筆記(入門篇)
ing Boot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來簡化新Spring應(yīng)用的初始搭建以及開發(fā)過程。這篇文章給大家?guī)砹藄pring boot 入門學(xué)習(xí)筆記,需要的朋友參考下2018-02-02spring data簡化jpa開發(fā)_動力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了spring data簡化jpa開發(fā),本文主要講述 Spring Data JPA,希望能夠深入學(xué)習(xí) Spring 和 JPA,有興趣的可以了解下2017-09-09