Java Http接口加签、验签操作

1、业务背景

最近接触了一些电商业务,发现在处理电商业务接口时,比如淘宝、支付类接口,接口双方为了确保数据参数在传输过程中未经过篡改,都需要对接口数据进行加签,然后在接口服务器端对接口参数进行验签,确保两个签名是一样的,验签通过之后再进行业务逻辑处理。我们这里主要介绍一下处理思路,至于签名算法我不做过多介绍,网上一大堆。

2、处理思路

双方约定好,参数按特定顺序排列,比如按首字母的顺序排列,如url:http://xxx/xxx.do?a=wersd&b=sd2354&c=4&signature=XXXXXXXXXXXX(signature为传入的签名),等你拿到入参后,将参数串a=wersd&b=sd2354&c=4按你们约定的签名规则,自己用md5加签一次,然后和入参的signature值对比,以确认调用者是否合法,这就是接口签名验证的思路。

3、实例练习

接口双方经过沟通,对接口达成如下共识:
1、注意事项,主要指接口的的协议、传入参数类型、签名算法、文件格式等说明

2、下面是一个电商业务接口的真实案例,双方约定好了接口URL、业务参数、固定参数、签名以及返回数据格式




接口调用时,接口调用方代码如下(仅供参考):
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入参:" + 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())) {
				//处理业务逻辑
				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;

	}


  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是C#加签Java验签SM2的示例代码: C#加签示例代码: ```csharp using System; using System.Security.Cryptography; using System.Text; namespace SM2Demo { class Program { static void Main(string[] args) { // 待签名的数据 string data = "Hello World!"; // 加载SM2证书 CngKey key = CngKey.Open("SM2Test"); // 创建SM2签名对象 ECDsaCng sm2 = new ECDsaCng(key); // 计算签名 byte[] signature = sm2.SignData(Encoding.UTF8.GetBytes(data)); // 输出签名结果 Console.WriteLine("Signature: " + Convert.ToBase64String(signature)); } } } ``` Java验签示例代码: ```java import java.security.*; import java.security.spec.ECGenParameterSpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; public class SM2Demo { public static void main(String[] args) throws Exception { // 待验签的数据 String data = "Hello World!"; // 加载SM2证书 KeyFactory keyFactory = KeyFactory.getInstance("EC"); byte[] privateKeyBytes = Base64.getDecoder().decode("MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgJzvJZJZJ5zJzJZJ5\n" + "zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ\n" + "5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ\n" + "5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJw=="); PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec); byte[] publicKeyBytes = Base64.getDecoder().decode("MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DfQADZGk+JzJZJ5zJzJZJ5zJzJZJ5zJzJ\n" + "ZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJ\n" + "ZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJ\n" + "ZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJw=="); X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes); PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); // 创建SM2验签对象 Signature signature = Signature.getInstance("SM3withSM2"); signature.initVerify(publicKey); // 验证签名 byte[] signatureBytes = Base64.getDecoder().decode("MEUCIQDQJzvJZJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJgIgQJzvJZJZJ5zJz\n" + "JZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJz\n" + "JZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJzJZJ5zJw=="); signature.update(data.getBytes()); boolean result = signature.verify(signatureBytes); // 输出验签结果 System.out.println("Verify result: " + result); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值