提交 | 用户 | age
|
9ec338
|
1 |
package com.hx.phip.interceptor; |
F |
2 |
|
|
3 |
import com.alibaba.fastjson.JSONObject; |
|
4 |
import com.hx.common.BaseController; |
|
5 |
import com.hx.exception.TipsException; |
da9ea8
|
6 |
import com.hx.phiappt.model.meiji.MjRequestLog; |
9ec338
|
7 |
import com.hx.phip.config.GlobalExceptionHandler; |
da9ea8
|
8 |
import com.hx.phip.service.meiji.MjRequestLogService; |
9ec338
|
9 |
import com.hx.redis.RedisUtil; |
F |
10 |
import com.hx.util.HttpServletRequestUtil; |
|
11 |
import com.hx.util.StringUtils; |
|
12 |
import com.platform.resultTool.PlatformCode; |
|
13 |
import lombok.SneakyThrows; |
|
14 |
import org.aspectj.lang.ProceedingJoinPoint; |
|
15 |
import org.aspectj.lang.annotation.Around; |
|
16 |
import org.aspectj.lang.annotation.Aspect; |
|
17 |
import org.aspectj.lang.annotation.Pointcut; |
|
18 |
import org.slf4j.Logger; |
|
19 |
import org.slf4j.LoggerFactory; |
|
20 |
import org.springframework.http.MediaType; |
|
21 |
import org.springframework.stereotype.Component; |
|
22 |
import org.springframework.web.context.request.RequestAttributes; |
|
23 |
import org.springframework.web.context.request.RequestContextHolder; |
|
24 |
import org.springframework.web.context.request.ServletRequestAttributes; |
|
25 |
import sun.misc.BASE64Decoder; |
|
26 |
|
|
27 |
import javax.annotation.Resource; |
|
28 |
import javax.servlet.http.HttpServletRequest; |
|
29 |
import java.io.BufferedReader; |
d66f76
|
30 |
import java.io.UnsupportedEncodingException; |
F |
31 |
import java.net.URLDecoder; |
9ec338
|
32 |
import java.net.URLEncoder; |
F |
33 |
import java.security.KeyFactory; |
|
34 |
import java.security.PublicKey; |
|
35 |
import java.security.Signature; |
|
36 |
import java.security.spec.X509EncodedKeySpec; |
|
37 |
import java.util.ArrayList; |
|
38 |
import java.util.Collections; |
|
39 |
import java.util.List; |
|
40 |
import java.util.Map; |
d66f76
|
41 |
import java.util.regex.Matcher; |
F |
42 |
import java.util.regex.Pattern; |
9ec338
|
43 |
|
F |
44 |
/** |
|
45 |
* 美际小肤 外部接口拦截器 |
|
46 |
* |
|
47 |
* @USER: fhx |
|
48 |
* @DATE: 2023/1/6 |
|
49 |
**/ |
|
50 |
@Aspect |
|
51 |
@Component |
|
52 |
public class MeiJiInterceptor extends BaseController { |
|
53 |
|
da9ea8
|
54 |
@Resource |
F |
55 |
private MjRequestLogService mjRequestLogService; |
|
56 |
|
9ec338
|
57 |
//机构公钥 |
F |
58 |
private static String jgPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7zFeslbt8BQ3FodPJXKILNQlZiLxmy0VJ6pWbcN/0UxNqoUMTw4IsGdCvJwlyRntL9WeGvrol9XirPH0dMAoua1xM9CkaTXI4dZnpoGVDsJxwQUi0Ld76pnpY8JfcKUZYCc4gGjqonzdIWK5DbK8VRzS2VsxgXG6yHv/HxyYNTQIDAQAB"; |
|
59 |
//加密算法 |
|
60 |
public static final String KEY_ALGORITHM = "RSA"; |
|
61 |
//签名算法 |
|
62 |
public static final String SIGNATURE_ALGORITHM = "SHA256WithRSA"; |
|
63 |
|
|
64 |
private static Logger logger = LoggerFactory.getLogger(MeiJiInterceptor.class.getName()); |
|
65 |
|
|
66 |
/** |
|
67 |
* 设置拦截的位置 |
|
68 |
* 拦截要校验的包 |
|
69 |
*/ |
|
70 |
@Pointcut("within(com.hx.phip.meiji..*))") |
|
71 |
public void checkSign() { |
|
72 |
System.out.println("拦截啦"); |
|
73 |
} |
|
74 |
|
|
75 |
/* *设置拦截的位置的操作 |
|
76 |
* @param joinPoint |
|
77 |
* @return |
|
78 |
* @throws Throwable*/ |
|
79 |
|
|
80 |
@Around("checkSign()") |
|
81 |
public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable { |
|
82 |
Object result = "SUCCESS"; |
da9ea8
|
83 |
//获取签名 |
F |
84 |
HttpServletRequest request = getRequest(); |
|
85 |
String method = request.getServletPath(); |
f1cda7
|
86 |
String bodyJson = ""; |
da9ea8
|
87 |
Integer status = MjRequestLog.STATUS_SUC; |
F |
88 |
String sign = request.getHeader("sign"); |
f1cda7
|
89 |
String errMsg = null; |
9ec338
|
90 |
try { |
F |
91 |
|
|
92 |
//判断请求类型 |
|
93 |
String contentType = request.getContentType(); |
|
94 |
if (StringUtils.noNull(contentType)) { |
|
95 |
contentType = contentType.toLowerCase(); |
|
96 |
} |
|
97 |
|
|
98 |
if (!MediaType.APPLICATION_JSON_VALUE.equals(contentType)) { |
|
99 |
throwParamException("请求数据格式非JSON格式!"); |
|
100 |
} |
|
101 |
|
da9ea8
|
102 |
|
9ec338
|
103 |
if (StringUtils.isEmpty(sign)) { |
F |
104 |
throwParamException("请求签名为空!"); |
|
105 |
} |
|
106 |
|
da9ea8
|
107 |
String str; |
9ec338
|
108 |
// 获取参数, 只取自定义的参数, 自带的HttpServletRequest, HttpServletResponse不管 |
F |
109 |
BufferedReader br = request.getReader(); |
|
110 |
while ((str = br.readLine()) != null) { |
da9ea8
|
111 |
bodyJson += str; |
9ec338
|
112 |
} |
F |
113 |
|
468c00
|
114 |
|
5e6f64
|
115 |
JSONObject body = JSONObject.parseObject(unicodeToCN(bodyJson)); |
da9ea8
|
116 |
|
468c00
|
117 |
//如果走的是皮肤报告接收接口,则参与验证签名的参数只是部分参数 |
F |
118 |
if(method.equals("/meiji/api/report/receive")){ |
|
119 |
//清除不参与验签的参数 |
|
120 |
body.remove("created_time"); |
|
121 |
body.remove("icon"); |
|
122 |
body.remove("share_url"); |
|
123 |
body.remove("resources"); |
|
124 |
body.remove("contents"); |
f8571e
|
125 |
body.remove("view_url"); |
468c00
|
126 |
} |
F |
127 |
|
9ec338
|
128 |
//验签 |
2ed344
|
129 |
verify(splicingParams(body), jgPublicKey, sign); |
9ec338
|
130 |
|
F |
131 |
result = joinPoint.proceed(); |
|
132 |
} catch (Exception e) { |
|
133 |
logger.error("美际拦截器异常!"); |
|
134 |
logger.error(GlobalExceptionHandler.getExceptionInformation(e)); |
f1cda7
|
135 |
errMsg = e.getMessage().length() > 255 ? e.getMessage().substring(0, 250) : e.getMessage(); |
9ec338
|
136 |
JSONObject data = new JSONObject(); |
F |
137 |
data.put("code", PlatformCode.ERROR_SYSTEM); |
f1cda7
|
138 |
data.put("message", errMsg); |
9ec338
|
139 |
result = data; |
da9ea8
|
140 |
status = MjRequestLog.STATUS_FAIL; |
9ec338
|
141 |
} finally { |
da9ea8
|
142 |
//新增请求日志 |
178a3f
|
143 |
mjRequestLogService.insert(new MjRequestLog(method, sign, unicodeToCN(bodyJson), errMsg, status)); |
9ec338
|
144 |
return result; |
F |
145 |
} |
|
146 |
|
|
147 |
} |
d66f76
|
148 |
|
f8571e
|
149 |
public static void main(String args[]) throws Exception { |
F |
150 |
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}]}"; |
|
151 |
JSONObject body = JSONObject.parseObject(unicodeToCN(s)); |
|
152 |
body.remove("created_time"); |
|
153 |
body.remove("icon"); |
|
154 |
body.remove("share_url"); |
|
155 |
body.remove("resources"); |
|
156 |
body.remove("contents"); |
|
157 |
body.remove("view_url"); |
|
158 |
String sign = "Wb1ZO6v+2ej9eRfs38mUs2dD4Yu7gJJncJHnbRSTDHj5WIK2uQWTe7Berz+heEfvFL/0j8Qx5jezcJoTgoM0hecYA09hKGSDwt2QeKt9BVchcNHvFDC+Aj56bqtB+/nZFbuY8+bfUTIL4xhFxVYznoV3ygY1Ktq2UEt+OY/uAgc="; |
|
159 |
verify(splicingParams(body), jgPublicKey, sign); |
d66f76
|
160 |
} |
F |
161 |
|
9ec338
|
162 |
|
da9ea8
|
163 |
//////////////////////////////////////////////////////////////// |
F |
164 |
|
9ec338
|
165 |
|
F |
166 |
/** |
|
167 |
* 拼接参数 |
|
168 |
* |
|
169 |
* @param params 参数 |
|
170 |
*/ |
|
171 |
@SneakyThrows |
|
172 |
public static String splicingParams(Map<String, Object> params) { |
|
173 |
List<String> keys = new ArrayList<>(params.keySet()); |
|
174 |
Collections.sort(keys); |
|
175 |
String prestr = ""; |
|
176 |
for (int i = 0; i < keys.size(); i++) { |
|
177 |
String key = keys.get(i); |
|
178 |
String value = params.get(key).toString(); |
3a2e4f
|
179 |
//对中文转码字符转为中文 |
F |
180 |
// value = unicodeToCN(value); |
9ec338
|
181 |
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符 |
F |
182 |
prestr = prestr + key + "=" + value; |
|
183 |
} else { |
|
184 |
prestr = prestr + key + "=" + value + "&"; |
|
185 |
} |
|
186 |
} |
|
187 |
return prestr; |
|
188 |
} |
|
189 |
|
|
190 |
|
|
191 |
/** |
|
192 |
* 验签 |
|
193 |
* |
|
194 |
* @param requestData 数据 |
|
195 |
* @param publicKey 公钥 |
|
196 |
* @param sign 数字签名 |
|
197 |
* @return |
|
198 |
* @throws Exception |
|
199 |
*/ |
|
200 |
public static void verify(String requestData, String publicKey, String sign) throws Exception { |
|
201 |
|
|
202 |
if (StringUtils.isEmpty(publicKey) || StringUtils.isEmpty(sign)) { |
|
203 |
throw new TipsException("参数异常!"); |
|
204 |
} |
|
205 |
|
|
206 |
//解密公钥 |
|
207 |
byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicKey); |
|
208 |
//构造X509EncodedKeySpec对象 |
|
209 |
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); |
|
210 |
//指定加密算法 |
|
211 |
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); |
|
212 |
//取公钥匙对象 |
|
213 |
PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec); |
|
214 |
|
|
215 |
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); |
|
216 |
signature.initVerify(publicKey2); |
|
217 |
signature.update(requestData.getBytes()); |
|
218 |
//验证签名是否正常 |
|
219 |
try { |
468c00
|
220 |
if(signature.verify(new BASE64Decoder().decodeBuffer(sign))){ |
F |
221 |
logger.info("==美际 验证签名成功=="); |
|
222 |
}else { |
|
223 |
throw new TipsException("== 美际 验签失败!=="); |
|
224 |
} |
9ec338
|
225 |
} catch (Exception e) { |
468c00
|
226 |
throw new TipsException(e.getMessage()); |
9ec338
|
227 |
} |
F |
228 |
} |
|
229 |
|
d66f76
|
230 |
/** |
F |
231 |
* Unicode转 汉字字符串 |
|
232 |
* |
|
233 |
* @param str |
|
234 |
* @return |
|
235 |
*/ |
|
236 |
public static String unicodeToCN(String str) { |
|
237 |
if(StringUtils.isEmpty(str)){ |
|
238 |
str = ""; |
|
239 |
} |
|
240 |
Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))"); |
|
241 |
Matcher matcher = pattern.matcher(str); |
|
242 |
char ch; |
|
243 |
while (matcher.find()) { |
|
244 |
ch = (char) Integer.parseInt(matcher.group(2), 16); |
|
245 |
str = str.replace(matcher.group(1), ch + ""); |
|
246 |
} |
|
247 |
return str; |
|
248 |
} |
|
249 |
|
|
250 |
/** |
|
251 |
* 中文转Unicode |
|
252 |
* 其他英文字母或特殊符号也可进行Unicode编码 |
|
253 |
* @param cn |
|
254 |
* @return |
|
255 |
*/ |
|
256 |
public static String cnToUnicode(String cn) { |
|
257 |
char[] chars = cn.toCharArray(); |
|
258 |
StringBuilder returnStr = new StringBuilder(); |
|
259 |
for (int i = 0; i < chars.length; i++) { |
|
260 |
returnStr.append("\\u").append(Integer.toString(chars[i], 16)); |
|
261 |
} |
|
262 |
return returnStr.toString(); |
|
263 |
} |
|
264 |
|
9ec338
|
265 |
} |