1. package com.xxx.util;
    2. import com.alibaba.fastjson.JSONObject;
    3. import com.fasterxml.jackson.databind.ObjectMapper;
    4. import org.apache.commons.codec.digest.DigestUtils;
    5. import org.apache.commons.lang3.StringUtils;
    6. import org.springframework.http.HttpMethod;
    7. import org.springframework.stereotype.Component;
    8. import javax.servlet.http.HttpServletRequest;
    9. import java.io.BufferedReader;
    10. import java.io.IOException;
    11. import java.io.InputStreamReader;
    12. import java.io.UnsupportedEncodingException;
    13. import java.net.URLDecoder;
    14. import java.nio.charset.StandardCharsets;
    15. import java.util.*;
    16. import java.util.stream.Collectors;
    17. /**
    18. * 接口验签
    19. * @author mafei
    20. * @vesion 1.0
    21. * @date 2022/6/27
    22. */
    23. @Component
    24. public class ApiSignUtil {
    25. private static String DEFAULT_APPID = "appid";
    26. // public static String DEFAULT_SECRET_KEY = "secretKey";
    27. private static String TIME_STAMP_KEY = "timeStamp";
    28. private static String SIGN_KEY = "sign";
    29. //超时时效,超过此时间认为签名过期
    30. private static Long EXPIRE_TIME = 5 * 60 * 1000L;
    31. // 从开放平台获取应用id
    32. private static String APPID = "APPID";
    33. // 从开放平台获取应用秘钥
    34. private static String SECRET_KEY = "SECRET_KEY";
    35. /**
    36. * 生成签名
    37. * @param param 对应实体类参数
    38. * @return
    39. */
    40. public static String getSignature(Object param) {
    41. ObjectMapper objectMapper = new ObjectMapper();
    42. Map params;
    43. try {
    44. String jsonStr = objectMapper.writeValueAsString(param);
    45. params = objectMapper.readValue(jsonStr, Map.class);
    46. } catch (Exception e) {
    47. throw new RuntimeException("生成签名:转换json失败");
    48. }
    49. // param参数要包含appid
    50. if (params.get(DEFAULT_APPID) == null) {
    51. params.put(DEFAULT_APPID, APPID);
    52. }
    53. // param参数要包含timeStamp
    54. if (params.get(TIME_STAMP_KEY) == null) {
    55. params.put(TIME_STAMP_KEY, System.currentTimeMillis());
    56. }
    57. //对map参数进行排序生成参数
    58. Set<String> keysSet = params.keySet();
    59. Object[] keys = keysSet.toArray();
    60. Arrays.sort(keys);
    61. String temp = Arrays.stream(keys)
    62. .map(key -> key + "=" + (!params.containsKey(key) ? "" : params.get(key)))
    63. .collect(Collectors.joining("&"));
    64. //根据参数生成签名
    65. String sign = DigestUtils.sha256Hex(temp + APPID + SECRET_KEY).toUpperCase();
    66. return sign;
    67. }
    68. /**
    69. * 校验签名,param参数中必须包含appid、timeStamp和sign(签名)
    70. */
    71. public static boolean checkSignature(OpenProp mrsProp, HttpServletRequest request) throws IOException {
    72. //获取request中的json参数转成map
    73. Map<String, Object> param = getAllParams(request);
    74. String sign = (String) param.get(SIGN_KEY);
    75. String appid = (String) param.get(DEFAULT_APPID);
    76. Long start = convertTimestamp(param.get(TIME_STAMP_KEY));
    77. long now = System.currentTimeMillis();
    78. //校验时间有效性
    79. if (start == null || now - start > EXPIRE_TIME || start - now > 0L) {
    80. return false;
    81. }
    82. //是否携带appid
    83. if (StringUtils.isBlank(appid)) {
    84. return false;
    85. }
    86. //是否携带签名
    87. if (StringUtils.isBlank(sign)) {
    88. return false;
    89. }
    90. //获取除签名外的参数
    91. param.remove(SIGN_KEY);
    92. //校验签名,服务端生成签名后和客户端做对比
    93. String signature = getSignature(mrsProp, param);
    94. if (sign.equals(signature)) {
    95. return true;
    96. }
    97. return false;
    98. }
    99. private static Long convertTimestamp(Object timestampObj) {
    100. return timestampObj != null ? Long.parseLong(timestampObj.toString()) : null;
    101. }
    102. /**
    103. * 将URL的参数和body参数合并
    104. * @param request
    105. */
    106. public static SortedMap<String, Object> getAllParams(HttpServletRequest request) throws IOException {
    107. SortedMap<String, Object> result = new TreeMap<>();
    108. //获取URL上的参数,并放入结果中
    109. result.putAll(getUrlParams(request));
    110. // get请求和DELETE请求不需要拿body参数
    111. if (!StringUtils.equalsAny(request.getMethod(), HttpMethod.GET.name(), HttpMethod.DELETE.name())) {
    112. Optional.ofNullable(getBodyParams(request))
    113. .ifPresent(result::putAll);
    114. }
    115. return result;
    116. }
    117. /**
    118. * 获取 Body 参数
    119. * @param request
    120. */
    121. public static Map<String, Object> getBodyParams(final HttpServletRequest request) throws IOException {
    122. BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
    123. String str = "";
    124. StringBuilder wholeStr = new StringBuilder();
    125. //一行一行的读取body体里面的内容;
    126. while ((str = reader.readLine()) != null) {
    127. wholeStr.append(str);
    128. }
    129. //转化成json对象
    130. return StringUtils.isNoneBlank(wholeStr) ? JSONObject.parseObject(wholeStr.toString(),Map.class) : new HashMap<>();
    131. }
    132. /**
    133. * 将URL请求参数转换成Map
    134. */
    135. public static Map<String, String> getUrlParams(HttpServletRequest request) {
    136. return Optional.ofNullable(request.getQueryString())
    137. .map(queryStr -> {
    138. try {
    139. return URLDecoder.decode(request.getQueryString(), String.valueOf(StandardCharsets.UTF_8));
    140. } catch (UnsupportedEncodingException e) {
    141. throw new RuntimeException(e);
    142. }
    143. })
    144. .map(params -> Arrays.stream(params.split("&"))
    145. .collect(Collectors.toMap(s -> s.substring(0, s.indexOf("=")), s -> s.substring(s.indexOf("=") + 1))))
    146. .orElse(new HashMap<>());
    147. }
    148. /**
    149. * 将map转换成url参数
    150. * @param map
    151. * @return
    152. */
    153. public static String getUrlParamsByMap(Map<String,Object> map) {
    154. if (map == null) {
    155. return "";
    156. }
    157. StringBuffer sb = new StringBuffer();
    158. for (Map.Entry<String,Object> entry : map.entrySet()) {
    159. sb.append(entry.getKey() + "=" + entry.getValue());
    160. sb.append("&");
    161. }
    162. String s = sb.toString();
    163. if (s.endsWith("&")) {
    164. s = StringUtils.substringBeforeLast(s, "&");
    165. }
    166. return s;
    167. }
    168. /*public static void test1(){
    169. AppSecretKey askid = apiSignUtil.appSecretKeyService.getByAttr("askid", 1);
    170. System.out.println("askid = " + askid);
    171. }*/
    172. /**
    173. * 生成签名
    174. */
    175. /*public static Map getSignature(Object param,String appid, String secretKey) {
    176. ObjectMapper objectMapper = new ObjectMapper();
    177. Map params;
    178. try {
    179. String jsonStr = objectMapper.writeValueAsString(param);
    180. params = objectMapper.readValue(jsonStr, Map.class);
    181. } catch (Exception e) {
    182. throw new RuntimeException("生成签名:转换json失败");
    183. }
    184. if (params.get(TIME_STAMP_KEY) == null) {
    185. params.put(TIME_STAMP_KEY, System.currentTimeMillis());
    186. }
    187. //对map参数进行排序生成参数
    188. Set<String> keysSet = params.keySet();
    189. Object[] keys = keysSet.toArray();
    190. Arrays.sort(keys);
    191. String temp = Arrays.stream(keys).map(key -> key + "=" + (!params.containsKey(key) ? "" : params.get(key)))
    192. .collect(Collectors.joining("&"));
    193. //根据参数生成签名
    194. String sign = DigestUtils.sha256Hex(temp + appid + secretKey).toUpperCase();
    195. // params.put(SIGN_KEY, sign);
    196. return params;
    197. }*/
    198. /**
    199. * 校验签名
    200. */
    201. /*public static boolean checkSignature(HttpServletRequest request,String appid, String secretKey) throws IOException {
    202. //获取request中的json参数转成map
    203. Map<String, Object> param = getAllParams(request);
    204. String sign = (String) param.get(SIGN_KEY);
    205. Long start = convertTimestamp(param.get(TIME_STAMP_KEY));
    206. long now = System.currentTimeMillis();
    207. //校验时间有效性
    208. if (start == null || now - start > EXPIRE_TIME || start - now > 0L) {
    209. return false;
    210. }
    211. //是否携带签名
    212. if (StringUtils.isBlank(sign)) {
    213. return false;
    214. }
    215. //获取除签名外的参数
    216. param.remove(SIGN_KEY);
    217. //校验签名
    218. Map paramMap = getSignature(param, appid,secretKey);
    219. String signature = (String) paramMap.get("sign");
    220. if (sign.equals(signature)) {
    221. return true;
    222. }
    223. return false;
    224. }*/
    225. }