OpenApiVerifyService.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. package com.zswl.dataservice.service.openApi;
  2. import cn.hutool.json.JSONObject;
  3. import cn.hutool.json.JSONUtil;
  4. import com.zswl.dataservice.auth.OpenAPIContext;
  5. import com.zswl.dataservice.dao.openApi.BlackListDao;
  6. import com.zswl.dataservice.dao.openApi.OpenApiRequestLogDao;
  7. import com.zswl.dataservice.dao.openApi.OpenApiSignInfoDao;
  8. import com.zswl.dataservice.dataConfig.OpenAPIConfig;
  9. import com.zswl.dataservice.domain.openApi.OpenApiRequestLog;
  10. import com.zswl.dataservice.domain.openApi.OpenApiSignInfo;
  11. import com.zswl.dataservice.service.base.RedisService;
  12. import com.zswl.dataservice.service.user.OperationLogsService;
  13. import com.zswl.dataservice.type.OperationLogType;
  14. import com.zswl.dataservice.utils.AesUtils;
  15. import com.zswl.dataservice.utils.DateUtils;
  16. import com.zswl.dataservice.utils.HttpUtils;
  17. import com.zswl.dataservice.utils.mqtt.type.LogsLevel;
  18. import com.zswl.dataservice.utils.net.IPUtil;
  19. import com.zswl.dataservice.utils.os.SystemUtil;
  20. import com.zswl.dataservice.utils.result.ResultContent;
  21. import jakarta.servlet.ServletInputStream;
  22. import jakarta.servlet.ServletOutputStream;
  23. import jakarta.servlet.http.HttpServletRequest;
  24. import jakarta.servlet.http.HttpServletResponse;
  25. import lombok.Data;
  26. import lombok.SneakyThrows;
  27. import lombok.extern.slf4j.Slf4j;
  28. import org.apache.commons.lang3.ObjectUtils;
  29. import org.apache.commons.lang3.StringUtils;
  30. import org.aspectj.apache.bcel.classfile.Module;
  31. import org.springframework.beans.factory.annotation.Autowired;
  32. import org.springframework.context.ApplicationContext;
  33. import org.springframework.http.HttpStatus;
  34. import org.springframework.stereotype.Service;
  35. import org.springframework.web.context.request.RequestContextHolder;
  36. import org.springframework.web.context.request.ServletRequestAttributes;
  37. import org.springframework.web.servlet.ModelAndView;
  38. import org.springframework.web.util.ContentCachingRequestWrapper;
  39. import org.springframework.web.util.ContentCachingResponseWrapper;
  40. import java.io.BufferedReader;
  41. import java.io.InputStreamReader;
  42. import java.io.OutputStream;
  43. import java.io.PrintWriter;
  44. import java.util.Date;
  45. import java.util.HashMap;
  46. import java.util.concurrent.ExecutorService;
  47. import java.util.concurrent.Executors;
  48. import java.util.concurrent.TimeUnit;
  49. /**
  50. * @author TRX
  51. * @date 2024/9/11
  52. */
  53. @Slf4j
  54. @Service
  55. public class OpenApiVerifyService {
  56. @Autowired
  57. private RedisService redisService;
  58. @Autowired
  59. private OpenApiRequestLogsService openApiRequestLogsService;
  60. @Autowired
  61. private OpenApiRequestLogDao openApiRequestLogDao;
  62. @Autowired
  63. OperationLogsService operationLogsService;
  64. @Autowired
  65. BlackListDao blackListDao;
  66. @Autowired
  67. OpenApiSignInfoDao openApiSignInfoDao;
  68. //线程池
  69. ExecutorService executorService = Executors.newFixedThreadPool(SystemUtil.getCpuCoreCount() * 2);
  70. @Autowired
  71. private void init(ApplicationContext applicationContext) {
  72. Runtime.getRuntime().addShutdownHook(new Thread(() -> {
  73. executorService.shutdownNow();
  74. }));
  75. }
  76. /**
  77. * 验证OpenAPI preHandle
  78. *
  79. * @param request
  80. * @param response
  81. * @param object
  82. * @return
  83. */
  84. @SneakyThrows
  85. public boolean verifyOpenAPI(HttpServletRequest request, HttpServletResponse response, Object object) {
  86. log.info("---------------------openAPI验证----------------------");
  87. OpenAPIContext.setTime(System.currentTimeMillis());
  88. if (request instanceof ContentCachingRequestWrapper) {
  89. ContentCachingRequestWrapper contentCachingRequestWrapper = (ContentCachingRequestWrapper) request;
  90. ContentCachingResponseWrapper responseWrapper = (ContentCachingResponseWrapper) response;
  91. String requestStr = contentCachingRequestWrapper.getContentAsString();
  92. String msg = "认证错误";
  93. int code = 403;
  94. boolean isSuccess = false;
  95. if (contentCachingRequestWrapper.getContentLength() > OpenAPIConfig.maxLen) {
  96. setResponse(request, responseWrapper, "请求内容过大", 403, false);
  97. return false;
  98. }
  99. log.info("请求数据requestStr: {}", requestStr);
  100. String authorization = request.getHeader("authorization");
  101. log.info("authorization数据 {}", authorization);
  102. if (StringUtils.isNotEmpty(authorization)) {
  103. if (authorization.length() > OpenAPIConfig.maxLen) {
  104. setResponse(request, responseWrapper, "请求内容过大", 403, false);
  105. return false;
  106. }
  107. authorization = authorization.replaceAll(" ", "");
  108. if (authorization.startsWith(OpenAPIConfig.OPENBODYSIG)) {
  109. authorization = authorization.replace(OpenAPIConfig.OPENBODYSIG, "");
  110. HashMap<String, String> map = new HashMap<>();
  111. String[] arr = authorization.split(",");
  112. isSuccess = true;
  113. if (arr.length > 0) {
  114. for (String s : arr) {
  115. for (String key : OpenAPIConfig.authKeys) {
  116. if (s.startsWith(key)) {
  117. String val = s.replace(key + "=", "");
  118. val = val.replace("\"", "");
  119. map.put(key, val);
  120. break;
  121. }
  122. }
  123. }
  124. }
  125. if (isSuccess) {
  126. OpenApiSignInfo signInfo = null;
  127. if (!map.containsKey("AppId")) {
  128. isSuccess = false;
  129. msg = "没有AppId信息";
  130. }
  131. String appId = map.get("AppId");
  132. signInfo = openApiSignInfoDao.findTopByAppId(appId);
  133. if (ObjectUtils.isEmpty(signInfo)) {
  134. isSuccess = false;
  135. msg = "AppId错误";
  136. }
  137. if (isSuccess && !map.containsKey("Timestamp")) {
  138. isSuccess = false;
  139. msg = "没有Timestamp信息";
  140. }
  141. String timestamp = map.get("Timestamp");
  142. if (StringUtils.isEmpty(timestamp) || timestamp.length() != 14) {
  143. isSuccess = false;
  144. msg = "Timestamp格式错误";
  145. }
  146. if (isSuccess){
  147. Long time = DateUtils.timeToLong(timestamp, DateUtils.unionAuth);
  148. if (time == null || Math.abs(time - System.currentTimeMillis()) > OpenAPIConfig.timeBetween) {
  149. isSuccess = false;
  150. msg = "Timestamp不符合要求";
  151. }
  152. }
  153. if (isSuccess && !map.containsKey("Nonce")) {
  154. isSuccess = false;
  155. msg = "没有Nonce信息";
  156. }
  157. String nonce = map.get("Nonce");
  158. if (isSuccess && (StringUtils.isEmpty(nonce) || nonce.length() > 50)) {
  159. isSuccess = false;
  160. msg = "Nonce为空或长度不符合要求";
  161. }
  162. if (isSuccess && !map.containsKey("Signature")) {
  163. isSuccess = false;
  164. msg = "没有Signature信息";
  165. }
  166. String signature = map.get("Signature");
  167. if (isSuccess && (StringUtils.isEmpty(signature) || signature.length() > 200)) {
  168. isSuccess = false;
  169. msg = "Signature为空或长度不符合要求";
  170. }
  171. if(isSuccess) {
  172. String sign = AesUtils.signData(requestStr);
  173. log.info("数据sign {}", sign);
  174. String appKey = signInfo.getAppKey();
  175. String c = String.format("%s%s%s%s", appId, timestamp, nonce, sign);
  176. String tempSignature = AesUtils.signMacSHA256(c, appKey);
  177. log.info("系统tempSignature {}", tempSignature);
  178. log.info("传入signature {}", signature);
  179. if (!tempSignature.equals(signature)) {
  180. isSuccess = false;
  181. msg = "Signature认证错误";
  182. }
  183. }
  184. }
  185. } else {
  186. msg = "报文头没有OPEN-BODY-SIG标记";
  187. }
  188. } else {
  189. msg = "报文头authorization为空";
  190. }
  191. if (!isSuccess) {
  192. // 验证不成功
  193. setResponse(request, responseWrapper, msg, code, true);
  194. return false;
  195. }
  196. }
  197. return true;
  198. }
  199. /**
  200. * 记录日志 postHandle
  201. *
  202. * @param request
  203. * @param response
  204. * @param handler
  205. * @param modelAndView
  206. */
  207. @SneakyThrows
  208. public void saveOpenAPILog(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
  209. ResultContent resultContent = null;
  210. if (response instanceof ContentCachingResponseWrapper) {
  211. ContentCachingResponseWrapper responseWrapper = (ContentCachingResponseWrapper) response;
  212. byte[] bytes = responseWrapper.getContentAsByteArray();
  213. resultContent = HttpUtils.toBean(new String(bytes), ResultContent.class);
  214. responseWrapper.copyBodyToResponse();
  215. }
  216. saveLog(request, resultContent);
  217. }
  218. public boolean isInBlackList(HttpServletRequest request) {
  219. String ip = IPUtil.getRemoteIp(request);
  220. if (blackListDao.existsByIp(ip)) {
  221. ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  222. RequestContextHolder.setRequestAttributes(servletRequestAttributes, true);//设置子线程共享
  223. executorService.execute(() -> {
  224. operationLogsService.addLogs(String.format("黑名单地址访问: %s", ip), LogsLevel.High, OperationLogType.Black, null);
  225. });
  226. return true;
  227. }
  228. return false;
  229. }
  230. @SneakyThrows
  231. private void setResponse(HttpServletRequest request, ContentCachingResponseWrapper responseWrapper, String msg, int code, boolean isSaveLog) {
  232. ResultContent resultContent = ResultContent.buildFail(msg, code);
  233. responseWrapper.setCharacterEncoding("UTF-8");
  234. responseWrapper.setHeader("Content-Type", "application/json");
  235. responseWrapper.setStatus(HttpStatus.PAYMENT_REQUIRED.value());
  236. PrintWriter printWriter = responseWrapper.getWriter();
  237. printWriter.write(JSONUtil.toJsonStr(resultContent));
  238. printWriter.flush();
  239. printWriter.close();
  240. responseWrapper.copyBodyToResponse();
  241. if (isSaveLog) {
  242. saveLog(request, resultContent);
  243. }
  244. resultContent = null;
  245. }
  246. private void saveLog(HttpServletRequest request, ResultContent resultContent) {
  247. OpenApiRequestLog openApiRequestLog = new OpenApiRequestLog();
  248. JSONObject param = HttpUtils.getRequestObj(request);
  249. if (param != null) {
  250. openApiRequestLog.setRequestBody(param);
  251. openApiRequestLog.setAppId(param.getStr("appId"));
  252. }
  253. Long startTime = OpenAPIContext.getTime();
  254. openApiRequestLog.setResponseTime(System.currentTimeMillis());
  255. if (startTime != null) {
  256. openApiRequestLog.setRequestTime(startTime);
  257. openApiRequestLog.setRequestTimeStr(DateUtils.paresTime(startTime, DateUtils.FORMAT_LONG));
  258. openApiRequestLog.setUserTime(System.currentTimeMillis() - startTime);
  259. }
  260. try {
  261. openApiRequestLog.setUa(request.getHeader("User-Agent"));
  262. openApiRequestLog.setIp(IPUtil.getRemoteIp(request));
  263. openApiRequestLog.setUrl(request.getRequestURI());
  264. } catch (Exception e) {
  265. e.printStackTrace();
  266. }
  267. openApiRequestLog.setAuthorization(request.getHeader("authorization"));
  268. openApiRequestLog.setTTL(new Date(System.currentTimeMillis() + OpenAPIConfig.logTTL));
  269. if (resultContent != null) {
  270. openApiRequestLog.setIsSuccess(resultContent.isSuccess());
  271. openApiRequestLog.setErrorMsg(resultContent.getMsg());
  272. }
  273. openApiRequestLog.setResponseBody(resultContent);
  274. openApiRequestLogDao.save(openApiRequestLog);
  275. }
  276. }