package com.hx.phip.interceptor;
|
|
import com.alibaba.fastjson.JSONObject;
|
import com.hx.common.BaseController;
|
import com.hx.exception.TipsException;
|
import com.hx.phiappt.model.meiji.MjRequestLog;
|
import com.hx.phip.config.GlobalExceptionHandler;
|
import com.hx.phip.service.meiji.MjRequestLogService;
|
import com.hx.redis.RedisUtil;
|
import com.hx.util.HttpServletRequestUtil;
|
import com.hx.util.StringUtils;
|
import com.platform.resultTool.PlatformCode;
|
import lombok.SneakyThrows;
|
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.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.http.MediaType;
|
import org.springframework.stereotype.Component;
|
import org.springframework.web.context.request.RequestAttributes;
|
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
import sun.misc.BASE64Decoder;
|
|
import javax.annotation.Resource;
|
import javax.servlet.http.HttpServletRequest;
|
import java.io.BufferedReader;
|
import java.io.UnsupportedEncodingException;
|
import java.net.URLDecoder;
|
import java.net.URLEncoder;
|
import java.security.KeyFactory;
|
import java.security.PublicKey;
|
import java.security.Signature;
|
import java.security.spec.X509EncodedKeySpec;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
|
/**
|
* 美际小肤 外部接口拦截器
|
*
|
* @USER: fhx
|
* @DATE: 2023/1/6
|
**/
|
@Aspect
|
@Component
|
public class MeiJiInterceptor extends BaseController {
|
|
@Resource
|
private MjRequestLogService mjRequestLogService;
|
|
//机构公钥
|
private static String jgPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7zFeslbt8BQ3FodPJXKILNQlZiLxmy0VJ6pWbcN/0UxNqoUMTw4IsGdCvJwlyRntL9WeGvrol9XirPH0dMAoua1xM9CkaTXI4dZnpoGVDsJxwQUi0Ld76pnpY8JfcKUZYCc4gGjqonzdIWK5DbK8VRzS2VsxgXG6yHv/HxyYNTQIDAQAB";
|
//加密算法
|
public static final String KEY_ALGORITHM = "RSA";
|
//签名算法
|
public static final String SIGNATURE_ALGORITHM = "SHA256WithRSA";
|
|
private static Logger logger = LoggerFactory.getLogger(MeiJiInterceptor.class.getName());
|
|
/**
|
* 设置拦截的位置
|
* 拦截要校验的包
|
*/
|
@Pointcut("within(com.hx.phip.meiji..*))")
|
public void checkSign() {
|
System.out.println("拦截啦");
|
}
|
|
/* *设置拦截的位置的操作
|
* @param joinPoint
|
* @return
|
* @throws Throwable*/
|
|
@Around("checkSign()")
|
public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
|
Object result = "SUCCESS";
|
//获取签名
|
HttpServletRequest request = getRequest();
|
String method = request.getServletPath();
|
String bodyJson = "";
|
Integer status = MjRequestLog.STATUS_SUC;
|
String sign = request.getHeader("sign");
|
String errMsg = null;
|
try {
|
|
//判断请求类型
|
String contentType = request.getContentType();
|
if (StringUtils.noNull(contentType)) {
|
contentType = contentType.toLowerCase();
|
}
|
|
if (!MediaType.APPLICATION_JSON_VALUE.equals(contentType)) {
|
throwParamException("请求数据格式非JSON格式!");
|
}
|
|
|
if (StringUtils.isEmpty(sign)) {
|
throwParamException("请求签名为空!");
|
}
|
|
String str;
|
// 获取参数, 只取自定义的参数, 自带的HttpServletRequest, HttpServletResponse不管
|
BufferedReader br = request.getReader();
|
while ((str = br.readLine()) != null) {
|
bodyJson += str;
|
}
|
|
|
JSONObject body = JSONObject.parseObject(unicodeToCN(bodyJson));
|
|
//如果走的是皮肤报告接收接口,则参与验证签名的参数只是部分参数
|
if(method.equals("/meiji/api/report/receive")){
|
//清除不参与验签的参数
|
body.remove("created_time");
|
body.remove("icon");
|
body.remove("share_url");
|
body.remove("resources");
|
body.remove("contents");
|
body.remove("view_url");
|
}
|
|
//验签
|
verify(splicingParams(body), jgPublicKey, sign);
|
|
result = joinPoint.proceed();
|
} catch (Exception e) {
|
logger.error("美际拦截器异常!");
|
logger.error(GlobalExceptionHandler.getExceptionInformation(e));
|
errMsg = e.getMessage().length() > 255 ? e.getMessage().substring(0, 250) : e.getMessage();
|
JSONObject data = new JSONObject();
|
data.put("code", PlatformCode.ERROR_SYSTEM);
|
data.put("message", errMsg);
|
result = data;
|
status = MjRequestLog.STATUS_FAIL;
|
} finally {
|
//新增请求日志
|
mjRequestLogService.insert(new MjRequestLog(method, sign, unicodeToCN(bodyJson), errMsg, status));
|
return result;
|
}
|
|
}
|
|
public static void main(String args[]) throws Exception {
|
String s = "{\"channel_id\":\"25853\",\"store_id\":\"007\",\"customer_id\":\"ac0adba7adab11ed91bf0c42a12ee9a2\",\"report_id\":\"25397711679918081\",\"scanner_id\":\"MEIJIXIAOFUQA001\",\"created_time\":1676969163,\"icon\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/icon.jpg\",\"view_url\":\"http:\\/\\/skin-view.myreal3d.com\\/skinPreview?scope=OPEN:basic&channel_id=25853&store_id=007&openid=ac0adba7adab11ed91bf0c42a12ee9a2&report_id=25397711679918081\",\"share_url\":\"http:\\/\\/dr2.myreal3d.com\\/skinReport?hash=EaB7sgdrZzVKVGl0&enable_history=1\",\"resources\":[{\"type\":\"zip\",\"flag\":\"obj\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/obj.zip\"},{\"type\":\"zip\",\"flag\":\"thumb\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/thumb.zip\"},{\"type\":\"zip\",\"flag\":\"mask\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/mask.zip\"},{\"type\":\"jpg\",\"flag\":\"rgb_cool\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Rgb_Cool.jpg\"},{\"type\":\"jpg\",\"flag\":\"rgb\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Rgb.jpg\"},{\"type\":\"jpg\",\"flag\":\"brown_face\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Brown_Face.jpg\"},{\"type\":\"jpg\",\"flag\":\"red\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Red.jpg\"},{\"type\":\"jpg\",\"flag\":\"red2_ex_face\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Red2_Ex_Face.jpg\"},{\"type\":\"jpg\",\"flag\":\"red2_face\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Red2_Face.jpg\"},{\"type\":\"jpg\",\"flag\":\"uv\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Uv.jpg\"},{\"type\":\"jpg\",\"flag\":\"uv_ex_face\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Uv_Ex_Face.jpg\"},{\"type\":\"jpg\",\"flag\":\"plh\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Plh.jpg\"},{\"type\":\"jpg\",\"flag\":\"plv\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Plv.jpg\"},{\"type\":\"jpg\",\"flag\":\"red2_heat\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Red2_Heat_Face.jpg\"},{\"type\":\"jpg\",\"flag\":\"brown_heat\",\"url\":\"https:\\/\\/external-storage-1251693531.cos.ap-shanghai.myqcloud.com\\/xiaofu\\/uploads\\/2023-02-21\\/25397711679918081\\/Brown_Heat_Face.jpg\"}],\"contents\":[{\"name\":\"抬头纹\",\"degree\":\"明显\",\"level\":2,\"result\":2.61},{\"name\":\"鱼尾纹\",\"degree\":\"中度\",\"level\":2,\"result\":2.41},{\"name\":\"眉间纹\",\"degree\":\"轻微\",\"level\":1,\"result\":4.1},{\"name\":\"痤疮\",\"degree\":\"Ⅰ级\",\"level\":1,\"result\":4.5},{\"name\":\"毛孔\",\"degree\":\"较粗大\",\"level\":1,\"result\":4.12},{\"name\":\"红血丝\",\"degree\":\"重度\",\"level\":3,\"result\":1.93},{\"name\":\"黑头\",\"degree\":\"无\",\"level\":0,\"result\":4.75},{\"name\":\"肤色不均\",\"degree\":\"中度\",\"level\":2,\"result\":2.37},{\"name\":\"眼下皱纹\",\"degree\":\"中度\",\"level\":2,\"result\":2.62},{\"name\":\"色斑\",\"degree\":\"中度\",\"level\":2,\"result\":3.44},{\"name\":\"泛红\",\"degree\":\"轻度\",\"level\":1,\"result\":3.6},{\"name\":\"T区出油\",\"degree\":\"无\",\"level\":0,\"result\":4.59},{\"name\":\"U区出油\",\"degree\":\"轻度\",\"level\":1,\"result\":4.11}]}";
|
JSONObject body = JSONObject.parseObject(unicodeToCN(s));
|
body.remove("created_time");
|
body.remove("icon");
|
body.remove("share_url");
|
body.remove("resources");
|
body.remove("contents");
|
body.remove("view_url");
|
String sign = "Wb1ZO6v+2ej9eRfs38mUs2dD4Yu7gJJncJHnbRSTDHj5WIK2uQWTe7Berz+heEfvFL/0j8Qx5jezcJoTgoM0hecYA09hKGSDwt2QeKt9BVchcNHvFDC+Aj56bqtB+/nZFbuY8+bfUTIL4xhFxVYznoV3ygY1Ktq2UEt+OY/uAgc=";
|
verify(splicingParams(body), jgPublicKey, sign);
|
}
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
/**
|
* 拼接参数
|
*
|
* @param params 参数
|
*/
|
@SneakyThrows
|
public static String splicingParams(Map<String, Object> params) {
|
List<String> keys = new ArrayList<>(params.keySet());
|
Collections.sort(keys);
|
String prestr = "";
|
for (int i = 0; i < keys.size(); i++) {
|
String key = keys.get(i);
|
String value = params.get(key).toString();
|
//对中文转码字符转为中文
|
// value = unicodeToCN(value);
|
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
|
prestr = prestr + key + "=" + value;
|
} else {
|
prestr = prestr + key + "=" + value + "&";
|
}
|
}
|
return prestr;
|
}
|
|
|
/**
|
* 验签
|
*
|
* @param requestData 数据
|
* @param publicKey 公钥
|
* @param sign 数字签名
|
* @return
|
* @throws Exception
|
*/
|
public static void verify(String requestData, String publicKey, String sign) throws Exception {
|
|
if (StringUtils.isEmpty(publicKey) || StringUtils.isEmpty(sign)) {
|
throw new TipsException("参数异常!");
|
}
|
|
//解密公钥
|
byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicKey);
|
//构造X509EncodedKeySpec对象
|
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
|
//指定加密算法
|
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
//取公钥匙对象
|
PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec);
|
|
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
|
signature.initVerify(publicKey2);
|
signature.update(requestData.getBytes());
|
//验证签名是否正常
|
try {
|
if(signature.verify(new BASE64Decoder().decodeBuffer(sign))){
|
logger.info("==美际 验证签名成功==");
|
}else {
|
throw new TipsException("== 美际 验签失败!==");
|
}
|
} catch (Exception e) {
|
throw new TipsException(e.getMessage());
|
}
|
}
|
|
/**
|
* Unicode转 汉字字符串
|
*
|
* @param str
|
* @return
|
*/
|
public static String unicodeToCN(String str) {
|
if(StringUtils.isEmpty(str)){
|
str = "";
|
}
|
Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
|
Matcher matcher = pattern.matcher(str);
|
char ch;
|
while (matcher.find()) {
|
ch = (char) Integer.parseInt(matcher.group(2), 16);
|
str = str.replace(matcher.group(1), ch + "");
|
}
|
return str;
|
}
|
|
/**
|
* 中文转Unicode
|
* 其他英文字母或特殊符号也可进行Unicode编码
|
* @param cn
|
* @return
|
*/
|
public static String cnToUnicode(String cn) {
|
char[] chars = cn.toCharArray();
|
StringBuilder returnStr = new StringBuilder();
|
for (int i = 0; i < chars.length; i++) {
|
returnStr.append("\\u").append(Integer.toString(chars[i], 16));
|
}
|
return returnStr.toString();
|
}
|
|
}
|