原理: 对原始数据 生成有序的json 字符串,然后取 摘要,然后 对摘要 进项 分对称加密。( 不对原数据加密是应为 原数据太大,加解密速度太慢,非对称加密都不 挺慢的。在摘要函数具有雪崩效应 ,原文发生点点的改变都会引起 摘要的剧烈变化 )
注意事项:因为使用的 对json 排序。而不是 传统的 from 表单方式。虽然 让请求响应都支持了json 变得统一,但是,这里又一个明显的容易缺陷。json 的 value 中 字符串带有 引号,数字类型没有引号。所以 这可能 应为 数据类型不一样造成验签失败。所以应该 全部使用 字符串。如果都有 引号就没有这种问题了。
备注:这个适用于 2个 系统之间 的数据交流。2 系统之间的数据交流最明显的特点就是 没有登录, 请求是无状态的,只能 通过请求参数来识别 请求是否合法。 这个 方式安全的 大前提 是自己的私钥 永远只有自己知道。
备注2: 这种方式侧重是数据不被篡改,而不是 保证数据不被泄露。 如果需要保证数据不被泄露 ,那么 发送请求和响应数据 的时候应该使用对方的公钥加密,对方收到请求以后使用自己的私钥解密。而且 加密的 原文 应该是整个 原始字符串,而不是 原文的摘要。
目录结构:
RSAUtils.java: 生成公私玥,加密解密 的工具类
package com.sbl.ebuygou.trading.biz.sign;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
public class RSAUtils {
public static final String CHARSET = "UTF-8";
public static final String RSA_ALGORITHM = "RSA";
public static Map<String, String> createKeys(int keySize){
//为RSA算法创建一个KeyPairGenerator对象
KeyPairGenerator kpg;
try{
kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
}catch(NoSuchAlgorithmException e){
throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
}
//初始化KeyPairGenerator对象,密钥长度
kpg.initialize(keySize);
//生成密匙对
KeyPair keyPair = kpg.generateKeyPair();
//得到公钥
Key publicKey = keyPair.getPublic();
String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
//得到私钥
Key privateKey = keyPair.getPrivate();
String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
Map<String, String> keyPairMap = new HashMap<String, String>();
keyPairMap.put("publicKey", publicKeyStr);
keyPairMap.put("privateKey", privateKeyStr);
return keyPairMap;
}
/**
* 得到公钥
* @param publicKey 密钥字符串(经过base64编码)
* @throws Exception
*/
public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
//通过X509编码的Key指令获得公钥对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
return key;
}
/**
* 得到私钥
* @param privateKey 密钥字符串(经过base64编码)
* @throws Exception
*/
public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
//通过PKCS#8编码的Key指令获得私钥对象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
return key;
}
/**
* 公钥加密
* @param data
* @param publicKey
* @return
*/
public static String publicEncrypt(String data, RSAPublicKey publicKey){
try{
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));
}catch(Exception e){
throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
}
}
/**
* 私钥解密
* @param data
* @param privateKey
* @return
*/
public static String privateDecrypt(String data, RSAPrivateKey privateKey){
try{
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET);
}catch(Exception e){
throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
}
}
/**
* 私钥加密
* @param data
* @param privateKey
* @return
*/
public static String privateEncrypt(String data, RSAPrivateKey privateKey){
try{
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength()));
}catch(Exception e){
throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
}
}
/**
* 公钥解密
* @param data
* @param publicKey
* @return
*/
public static String publicDecrypt(String data, RSAPublicKey publicKey){
try{
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET);
}catch(Exception e){
throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
}
}
private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){
int maxBlock = 0;
if(opmode == Cipher.DECRYPT_MODE){
maxBlock = keySize / 8;
}else{
maxBlock = keySize / 8 - 11;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] buff;
int i = 0;
try{
while(datas.length > offSet){
if(datas.length-offSet > maxBlock){
buff = cipher.doFinal(datas, offSet, maxBlock);
}else{
buff = cipher.doFinal(datas, offSet, datas.length-offSet);
}
out.write(buff, 0, buff.length);
i++;
offSet = i * maxBlock;
}
}catch(Exception e){
throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e);
}
byte[] resultDatas = out.toByteArray();
IOUtils.closeQuietly(out);
return resultDatas;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
SignUtil.java : 签名和核心 工具类
package com.sbl.ebuygou.trading.biz.sign;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import org.apache.commons.codec.digest.DigestUtils;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.sbl.ebuygou.trading.biz.sign.pram.QueryOrderReq;
/**
* 签名工具
*
* @author ZHANGYUKUN
*
*/
public class SignUtil {
/**
* 生成签名
*
* @param sortData
* 原始加密字符串
* @param privateKeyStr
* 私钥字符串
* @return 加密后的 对象
*/
public static <T extends SignParam> T getSignObject(T signParam, String privateKeyStr) {
String sign = getSign(signParam, privateKeyStr);
signParam.setSign(sign);
return signParam;
}
/**
* 生成签名
*
* @param sortData
* 原始加密字符串
* @param privateKeyStr
* 私钥字符串
* @return 加密后的 sign字符串
*/
public static <T extends SignParam> String getSign(T signParam, String privateKeyStr) {
String sortData = getSortData(signParam);
RSAPrivateKey privateKey = null;
try {
privateKey = RSAUtils.getPrivateKey(privateKeyStr);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
String sortDataMd5 = DigestUtils.md5Hex(sortData);
return RSAUtils.privateEncrypt(sortDataMd5, privateKey);
}
/**
* 核对签名
*
* @param resultStr
* 带有 sign 的json 字符串
* @param publicKeyStr
* 公钥字符串
* @return
*/
public static <T extends SignParam > boolean checkSign(String resultStr,String publicKeyStr , TypeReference< T > typeReference) {
Content content = SignUtil.getSortData(resultStr, typeReference );
return checkSign(content.getSortData(), content.getSign(),publicKeyStr);
}
/**
* 核对签名
*
* @param sortData
* 原始加密字符串
* @param sige
* 签名字符串
* @param publicKeyStr
* 公钥字符串
*
* @return true 验签成功 ,false 验签失败
*/
public static boolean checkSign(String sortData, String sige, String publicKeyStr) {
RSAPublicKey publicKey = null;
try {
publicKey = RSAUtils.getPublicKey(publicKeyStr);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
String data = null;
try {
data = RSAUtils.publicDecrypt(sige, publicKey);
} catch (Exception e) {
e.printStackTrace();
return false;
}
String sortDataMd5 = DigestUtils.md5Hex(sortData);
if (data.equals(sortDataMd5)) {
return true;
}
return false;
}
/**
* 得到排序的 用于签名的 原始 json 字符串
*
* @param signParam
* 可以签名的对象
* @return 排序了的 原始 加密字符串
*/
public static <T extends SignParam> String getSortData(T signParam) {
signParam.setSign(null);
return JSONObject.toJSONString(signParam, SerializerFeature.SortField);
}
/**
* 得到排序的 用于签名的 原始 json 字符串
*
* @param resultStr
* 带有 签名的 原始字符串
* @return Content 里面带有 原始签名字符串 和签名
*/
public static <T extends SignParam> Content getSortData(String resultStr, TypeReference<T> typeReference) {
T signResult = JSONObject.parseObject(resultStr, typeReference);
String sign = signResult.getSign();
signResult.setSign(null);
String sortData = getSortData(signResult);
Content content = new Content();
content.setSign(sign);
content.setSortData(sortData);
return content;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
Content.java: 存放 原始签名 json 字符串和 签名 的 辅助类
package com.sbl.ebuygou.trading.biz.sign;
public class Content {
/**
* 签名
*/
private String sign;
/**
* 原始的 签名 json 字符串
*/
private String sortData;
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getSortData() {
return sortData;
}
public void setSortData(String sortData) {
this.sortData = sortData;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
RSAKey.java: 存放 公私玥的地方( 我这里省事就只用了一组公私玥,正常应该2 对 , 各自 持有自己的私钥,公钥 ,和对方的 公钥)
package com.sbl.ebuygou.trading.biz.sign;
public class RSAKey {
public static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCWLw2S_98GLHAe3ZvVCh3rdJ36A0BHwLehAK5j1378peDDOdz1oIsHyprRsGvnXh9aWZAhKemIUkimK-WtbD4VVmOsfayoSL17c_CZIL7Yd6tfSBiobbXb4m-bt0wGZRzh0L7IMpwIukzmWcyo0BNGdEe6CLDb6gvc6IOwJ_JBuQIDAQAB";
public static final String privateKey ="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJYvDZL_3wYscB7dm9UKHet0nfoDQEfAt6EArmPXfvyl4MM53PWgiwfKmtGwa-deH1pZkCEp6YhSSKYr5a1sPhVWY6x9rKhIvXtz8Jkgvth3q19IGKhttdvib5u3TAZlHOHQvsgynAi6TOZZzKjQE0Z0R7oIsNvqC9zog7An8kG5AgMBAAECgYADa0bP1etp5JEY4sqtavGLbrg5_OD1wTls_Or7cuh9L_mR-DtDjEgeAUrNA0sxlT75e5iAaMfcRqNIxS8RZ6lyIfhaRlzV2L0baBzL718INpHuc5_zqxX1aFIKScQylX4YAVGwk4AG6NU9rlzNd8wHqH9P7lFQdfsc_cd72CQE0QJBAM8o_hfIUxIHdfNFpvMTkZ9-xEHlDBOaQkjWMu7WCHQ1xiNMR1stSqHLItyG3vk4N3MISAyY9L270dy3E_hR9OsCQQC5l0sZ3L9TB6tibzo2xL39jeOCA7BrrFSThF81KRAujlCgHcKGV64po6YLmjxaX5z77xJOPSyc8YGgppVjH8rrAkEAq_6Q2BYOQk3HdC9EKVT59r49G6ibmjrdBbQxnXI-mp164BuYsu6rpCEP1KB1x90QzIT3rN3hdRXXa7Tk86q3-QJAWCZcLXSEC1PhO2fJJqpb80qpfN9ztDCuG0MMVZuja_l8ohCAjH6o4m4wN-KSN_qh_aeX8kFsJz8uare0zNgU8QJAEZroY4DiiFdIxIA2S5gKDcvZlkl6ePSZzMbPw35wVrE9NqqL7l3S1TfZ9PnAhU70S2IW0ZMM0DdiAX5-zb3t_A";
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
SignParam.java:定义的统一的可以签名的对象的抽象(请求对象和响应对象都应该继承这个类 )。
package com.sbl.ebuygou.trading.biz.sign;
/**
* 带有签名的参数
* @author ZHANGYUKUN
*
*/
public abstract class SignParam {
/**
* 签名
*/
private String sign;
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
上面5 个类是固定的。下面的类根据业务自由拓展.
QueryOrderReq.java : 查询订单请求参数( 不同 的 请求定义不通接请求参数 )
package com.sbl.ebuygou.trading.biz.sign.pram;
import com.sbl.ebuygou.trading.biz.sign.SignParam;
/**
* 查询订单请求
* @author ZHANGYUKUN
*
*/
public class QueryOrderReq extends SignParam {
/**
* 订单Id
*/
private String orderId;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
SignResult.java:带有签名的 统一返回 ,请求 没有固定格式,为了拓展,返回 固定格式便于对方解析( 备注:请求是多变的,但是响应 都是类似的。 基本都是 有个状态,有个原因 ,有个数据 )。
package com.sbl.ebuygou.trading.biz.sign.pram;
import com.sbl.ebuygou.trading.biz.sign.RSAKey;
import com.sbl.ebuygou.trading.biz.sign.SignParam;
import com.sbl.ebuygou.trading.biz.sign.SignUtil;
/**
* 签名的结果集
*
* @author ZHANGYUKUN
*
* @param <T>
*/
public class SignResult<T> extends SignParam {
/**
* 状态
*/
private Status status;
/**
* 备注
*/
private String mark;
/**
* 数据
*/
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public String getMark() {
return mark;
}
public void setMark(String mark) {
this.mark = mark;
}
/**
* 得到一个成功的结果集
*
* @param data 数据
* @param privateKeyStr 私钥字符串
* @return
*/
public static <T> SignResult<T> getSucceedInstance(T data, String privateKeyStr ) {
SignResult<T> signResult = new SignResult<T>();
signResult.setMark("成功");
signResult.setStatus( Status.SUCCEE );
signResult.setData(data);
signResult = SignUtil.getSignObject(signResult, RSAKey.privateKey );
return signResult;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
Status.java :统一的 响应状态
测试类:OrderPublicController.java
package com.sbl.ebuygou.trading.biz.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.sbl.commons.exception.resolver.exception.ParameterErrorException;
import com.sbl.commons.util.BeanUtils;
import com.sbl.ebuygou.platform.api.api.SupplierServiceApi;
import com.sbl.ebuygou.platform.api.api.UserServiceApi;
import com.sbl.ebuygou.trading.biz.bean.in.QueryOrderItemIn;
import com.sbl.ebuygou.trading.biz.bean.out.OrderItemOut;
import com.sbl.ebuygou.trading.biz.bean.out.OrderOut;
import com.sbl.ebuygou.trading.biz.entity.Order;
import com.sbl.ebuygou.trading.biz.service.LogisticsService;
import com.sbl.ebuygou.trading.biz.service.OrderService;
import com.sbl.ebuygou.trading.biz.sign.RSAKey;
import com.sbl.ebuygou.trading.biz.sign.SignUtil;
import com.sbl.ebuygou.trading.biz.sign.pram.QueryOrderReq;
import com.sbl.ebuygou.trading.biz.sign.pram.SignResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* 订单相关接口
*
* @author ZHANGYUKUN
*
*/
@Api(tags = "订单相关接口(三方调用)")
@RestController
@RequestMapping("public/order")
public class OrderPublicController {
@Autowired
OrderService orderService;
@Autowired
LogisticsService logisticsService;
@Autowired
SupplierServiceApi supplierServiceApi;
@Autowired
UserServiceApi userServiceApi;
@ApiOperation("测试甲方接受乙方请求,然后验签,并且放回响应乙方签名数据")
@GetMapping("queryOrderByIdWithOrderItem")
public SignResult<OrderOut> queryByOrderId(@RequestBody QueryOrderReq queryOrderReq ) {
String resultStr = JSONObject.toJSONString( queryOrderReq );
if( !SignUtil.checkSign( resultStr ,RSAKey.publicKey ,new TypeReference< QueryOrderReq >() {} ) ) {
throw new ParameterErrorException("验签失败");
}
//业务逻辑
long orderId = Long.valueOf( queryOrderReq.getOrderId() );
OrderOut orderOut = new OrderOut();
Order order = orderService.queryOrderById( orderId );
if (order == null) {
return null;
}
BeanUtils.copyProperties(order, orderOut, true);
// 关联子订单
QueryOrderItemIn queryOrderItemIn = new QueryOrderItemIn();
queryOrderItemIn.setOrderId( orderId );
orderOut.setOrderItem(BeanUtils.copyToOutList(orderService.queryOrderItemByOrderId(queryOrderItemIn, order.getUserId()), OrderItemOut.class));
return SignResult.getSucceedInstance(orderOut , RSAKey.privateKey );
}
@ApiOperation("测试乙方验签")
@GetMapping("checkSign")
public boolean checkSign(String orderId) {
SignResult<OrderOut> signResult = t1( orderId );
String resultStr = JSONObject.toJSONString( signResult );
return SignUtil.checkSign( resultStr , RSAKey.publicKey , new TypeReference< SignResult<OrderOut> >() {} );
}
@ApiOperation("测试乙方发送 签名数据给 甲方")
@GetMapping("t1")
public SignResult<OrderOut> t1(String orderId ) {
QueryOrderReq queryOrderReq = new QueryOrderReq();
queryOrderReq.setOrderId(orderId);
return queryByOrderId( SignUtil.getSignObject( queryOrderReq, RSAKey.privateKey ) );
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
备注。SignResult<OrderOut> 里面的 OrderOut 我就不上传了。根据自己的业务定义就是了。