记得上下班打卡 | git大法好,push需谨慎

Commit 439f0f9f authored by anjiabin's avatar anjiabin

增加订单请求解密

parent aba76200
......@@ -29,6 +29,11 @@
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
</dependencies>
......
package com.liquidnet.service.base.codec.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @description: 该注解表明请求中的数据是加密的,需要进行解密
* @author: DFY
* @time: 2020/3/30 10:58
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DecryptAndVerify {
/** 解密后的参数类型 */
Class<?> decryptedClass();
}
package com.liquidnet.service.base.codec.aspect;
import com.alibaba.fastjson.JSON;
import com.liquidnet.service.base.codec.annotation.DecryptAndVerify;
import com.liquidnet.service.base.codec.exception.DecryptAndVerifyException;
import com.liquidnet.service.base.codec.util.CodecUtil;
import com.liquidnet.service.base.codec.vo.EncryptedReq;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
/**
* @description: 加密请求解密及验证切面
* @author: DFY
* @time: 2020/3/30 11:18
*/
@Slf4j
@Aspect
@Component
public class DecryptAndVerifyAspect {
@Pointcut("@annotation(com.liquidnet.service.base.codec.annotation.DecryptAndVerify)")
public void pointCut() {}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
if (args == null || args.length == 0) {
throw new DecryptAndVerifyException(joinPoint.getSignature().getName() + ",参数为空");
}
EncryptedReq encryptedReq = null;
for (Object obj : args) {
if (obj instanceof EncryptedReq) {
encryptedReq = (EncryptedReq) obj;
break;
}
}
if (encryptedReq == null) {
throw new DecryptAndVerifyException(joinPoint.getSignature().getName() + ",参数中无待解密类");
}
String decryptedData = decryptAndVerify(encryptedReq);
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
DecryptAndVerify annotation = methodSignature.getMethod().getAnnotation(DecryptAndVerify.class);
if (annotation == null || annotation.decryptedClass() == null) {
throw new DecryptAndVerifyException(joinPoint.getSignature().getName() + ",未指定解密类型");
}
encryptedReq.setData(JSON.parseObject(decryptedData, annotation.decryptedClass()));
return joinPoint.proceed();
}
private String decryptAndVerify(EncryptedReq encryptedReq) {
String sign = CodecUtil.sha1Encrypt(encryptedReq.getEncryptedData() + encryptedReq.getTimestamp());
if (sign.equals(encryptedReq.getSign())) {
return CodecUtil.aesDecrypt(encryptedReq.getEncryptedData());
} else {
throw new DecryptAndVerifyException("验签失败:" + JSON.toJSONString(encryptedReq));
}
}
}
package com.liquidnet.service.base.codec.exception;
/**
* @description: 解密验证异常
* @author: DFY
* @time: 2020/3/30 13:58
*/
public class DecryptAndVerifyException extends RuntimeException {
public DecryptAndVerifyException(String message) {
super(message);
}
}
package com.liquidnet.service.base.codec.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
* @description: 加解密工具类
* @author: DFY
* @time: 2020/3/30 10:25
*/
@Slf4j
public class CodecUtil {
/** AES加密密钥 */
public static final byte[] AES_SECRET_KEY_BYTES = Base64Utils.decodeFromString("XjjkaLnlzAFbR399IP4kdQ==");
/** SHA1加密密钥(用于增加加密的复杂度) */
public static final String SHA1_SECRET_KEY = "QGZUanpSaSy9DEPQFVULJQ==";
/**
* 对数据进行加密,用AES加密再用Base64编码
* @param data 待加密数据
* @return
*/
public static String aesEncrypt(String data) {
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // 加密算法/工作模式/填充方式
byte[] dataBytes = data.getBytes();
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(AES_SECRET_KEY_BYTES, "AES"));
byte[] result = cipher.doFinal(dataBytes);
return Base64Utils.encodeToString(result);
} catch (Exception e) {
log.error("执行CodecUtil.aesEncrypt失败:data={},异常:{}", data, e);
}
return null;
}
/**
* 对数据进行加密,用AES解密
* @param encryptedDataBase64
* @return
*/
public static String aesDecrypt(String encryptedDataBase64) {
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // 加密算法/工作模式/填充方式
byte[] dataBytes = Base64Utils.decodeFromString(encryptedDataBase64);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(AES_SECRET_KEY_BYTES, "AES"));
byte[] result = cipher.doFinal(dataBytes);
return new String(result);
} catch (Exception e) {
log.error("执行CodecUtil.aesDecrypt失败:data={},异常:{}", encryptedDataBase64, e);
}
return null;
}
/**
* 对数据进行加密,用SHA1加密再转换为16进制
* @param data
* @return
*/
public static String sha1Encrypt(String data) {
return DigestUtils.sha1Hex(data + SHA1_SECRET_KEY);
}
/** AES密钥长度,支持128、192、256 */
private static final int AES_SECRET_KEY_LENGTH = 128;
private static String generateAESSecretKeyBase64(String key) {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(AES_SECRET_KEY_LENGTH);
SecretKey secretKey = keyGenerator.generateKey();
return Base64Utils.encodeToString(secretKey.getEncoded());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws Exception {
System.out.println("CodecUtil.AES_SECRET_KEY_BYTES=== "+Base64Utils.encodeToString(CodecUtil.AES_SECRET_KEY_BYTES));
// System.out.println(sha1Encrypt("this is a test"));
// long timestamp = System.currentTimeMillis();
// System.out.println("时间戳:" + timestamp);
//// UserLoginReq userLoginReq = new UserLoginReq("admin", "admin");
//// String data = JSON.toJSONString(userLoginReq);
// String data = "{\"number\":1,\"ticketId\":\"2811887059054592999181\",\"isElectronic\":1,\"isExpress\":0,\"deviceFrom\":\"wap\",\"actual\":0.01,\"performanceId\":\"2811713813327872196937\",\"timeId\":\"2811766812553216086853\",\"returnUrl\":\"http://testm.zhengzai.tv/#/order/status?order_type=ticket&order_id=\",\"showUrl\":\"http://testm.zhengzai.tv/#/order/status?order_type=ticket&order_id=\",\"expressType\":2,\"agentId\":0,\"payType\":\"alipay\"}";
// System.out.println("加密前的数据:" + data);
// String encryptedData = CodecUtil.aesEncrypt(data);
// System.out.println("加密后的数据:" + encryptedData);
// String sign = CodecUtil.sha1Encrypt(encryptedData + timestamp);
// System.out.println("签名:" + sign);
// EncryptedReq<PayOrderParam> encryptedReq = new EncryptedReq<>();
// encryptedReq.setEncryptedData(encryptedData);
// encryptedReq.setTimestamp(timestamp);
// encryptedReq.setSign(sign);
// System.out.println("加密后的请求:" + JSON.toJSONString(encryptedReq));
}
}
package com.liquidnet.service.base.codec.vo;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @description: 加密请求
* @author: DFY
* @time: 2020/3/30 10:16
*/
@Data
public class EncryptedReq<T> {
/** 签名 */
@NotBlank(message = "用户签名不能为空")
private String sign;
/** 加密请求数据 */
@NotBlank(message = "加密请求不能为空")
private String encryptedData;
/** 原始请求数据(解密后回填到对象) */
private T data;
/** 请求的时间戳 */
@NotNull(message = "时间戳不能为空")
private Long timestamp;
}
......@@ -3,6 +3,8 @@ package com.liquidnet.service.order.controller;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.codec.annotation.DecryptAndVerify;
import com.liquidnet.service.base.codec.vo.EncryptedReq;
import com.liquidnet.service.kylin.dto.param.PayAgainParam;
import com.liquidnet.service.kylin.dto.param.PayOrderParam;
import com.liquidnet.service.kylin.dto.param.SyncOrderParam;
......@@ -36,13 +38,22 @@ public class KylinOrderTicketsController {
@Autowired
IKylinOrderTicketsOrderService orderTicketsOrderService;
@DecryptAndVerify(decryptedClass = PayOrderParam.class)
@PostMapping("pre")
@ApiOperation("下单")
@ApiResponse(code = 200, message = "接口返回对象参数")
public ResponseDto<PayResultVo> checkCanOrder(@RequestBody @Valid PayOrderParam payOrderParam) {
public ResponseDto<PayResultVo> checkCanOrder(@RequestBody @Valid EncryptedReq<PayOrderParam> encryptedReq) {
PayOrderParam payOrderParam = encryptedReq.getData();
return orderTicketsOrderService.checkCanOrder(payOrderParam);
}
// @PostMapping("pre")
// @ApiOperation("下单")
// @ApiResponse(code = 200, message = "接口返回对象参数")
// public ResponseDto<PayResultVo> checkCanOrder(@RequestBody @Valid PayOrderParam payOrderParam) {
// return orderTicketsOrderService.checkCanOrder(payOrderParam);
// }
@PostMapping("payAgain")
@ApiOperation("再次支付")
@ApiResponse(code = 200, message = "接口返回对象参数")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment