package com.xxx.util;import com.alibaba.fastjson.JSONObject;import com.fasterxml.jackson.databind.ObjectMapper;import org.apache.commons.codec.digest.DigestUtils;import org.apache.commons.lang3.StringUtils;import org.springframework.http.HttpMethod;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.net.URLDecoder;import java.nio.charset.StandardCharsets;import java.util.*;import java.util.stream.Collectors;/** * 接口验签 * @author mafei * @vesion 1.0 * @date 2022/6/27 */@Componentpublic class ApiSignUtil { private static String DEFAULT_APPID = "appid"; // public static String DEFAULT_SECRET_KEY = "secretKey"; private static String TIME_STAMP_KEY = "timeStamp"; private static String SIGN_KEY = "sign"; //超时时效,超过此时间认为签名过期 private static Long EXPIRE_TIME = 5 * 60 * 1000L; // 从开放平台获取应用id private static String APPID = "APPID"; // 从开放平台获取应用秘钥 private static String SECRET_KEY = "SECRET_KEY"; /** * 生成签名 * @param param 对应实体类参数 * @return */ public static String getSignature(Object param) { ObjectMapper objectMapper = new ObjectMapper(); Map params; try { String jsonStr = objectMapper.writeValueAsString(param); params = objectMapper.readValue(jsonStr, Map.class); } catch (Exception e) { throw new RuntimeException("生成签名:转换json失败"); } // param参数要包含appid if (params.get(DEFAULT_APPID) == null) { params.put(DEFAULT_APPID, APPID); } // param参数要包含timeStamp if (params.get(TIME_STAMP_KEY) == null) { params.put(TIME_STAMP_KEY, System.currentTimeMillis()); } //对map参数进行排序生成参数 Set<String> keysSet = params.keySet(); Object[] keys = keysSet.toArray(); Arrays.sort(keys); String temp = Arrays.stream(keys) .map(key -> key + "=" + (!params.containsKey(key) ? "" : params.get(key))) .collect(Collectors.joining("&")); //根据参数生成签名 String sign = DigestUtils.sha256Hex(temp + APPID + SECRET_KEY).toUpperCase(); return sign; } /** * 校验签名,param参数中必须包含appid、timeStamp和sign(签名) */ public static boolean checkSignature(OpenProp mrsProp, HttpServletRequest request) throws IOException { //获取request中的json参数转成map Map<String, Object> param = getAllParams(request); String sign = (String) param.get(SIGN_KEY); String appid = (String) param.get(DEFAULT_APPID); Long start = convertTimestamp(param.get(TIME_STAMP_KEY)); long now = System.currentTimeMillis(); //校验时间有效性 if (start == null || now - start > EXPIRE_TIME || start - now > 0L) { return false; } //是否携带appid if (StringUtils.isBlank(appid)) { return false; } //是否携带签名 if (StringUtils.isBlank(sign)) { return false; } //获取除签名外的参数 param.remove(SIGN_KEY); //校验签名,服务端生成签名后和客户端做对比 String signature = getSignature(mrsProp, param); if (sign.equals(signature)) { return true; } return false; } private static Long convertTimestamp(Object timestampObj) { return timestampObj != null ? Long.parseLong(timestampObj.toString()) : null; } /** * 将URL的参数和body参数合并 * @param request */ public static SortedMap<String, Object> getAllParams(HttpServletRequest request) throws IOException { SortedMap<String, Object> result = new TreeMap<>(); //获取URL上的参数,并放入结果中 result.putAll(getUrlParams(request)); // get请求和DELETE请求不需要拿body参数 if (!StringUtils.equalsAny(request.getMethod(), HttpMethod.GET.name(), HttpMethod.DELETE.name())) { Optional.ofNullable(getBodyParams(request)) .ifPresent(result::putAll); } return result; } /** * 获取 Body 参数 * @param request */ public static Map<String, Object> getBodyParams(final HttpServletRequest request) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); String str = ""; StringBuilder wholeStr = new StringBuilder(); //一行一行的读取body体里面的内容; while ((str = reader.readLine()) != null) { wholeStr.append(str); } //转化成json对象 return StringUtils.isNoneBlank(wholeStr) ? JSONObject.parseObject(wholeStr.toString(),Map.class) : new HashMap<>(); } /** * 将URL请求参数转换成Map */ public static Map<String, String> getUrlParams(HttpServletRequest request) { return Optional.ofNullable(request.getQueryString()) .map(queryStr -> { try { return URLDecoder.decode(request.getQueryString(), String.valueOf(StandardCharsets.UTF_8)); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } }) .map(params -> Arrays.stream(params.split("&")) .collect(Collectors.toMap(s -> s.substring(0, s.indexOf("=")), s -> s.substring(s.indexOf("=") + 1)))) .orElse(new HashMap<>()); } /** * 将map转换成url参数 * @param map * @return */ public static String getUrlParamsByMap(Map<String,Object> map) { if (map == null) { return ""; } StringBuffer sb = new StringBuffer(); for (Map.Entry<String,Object> entry : map.entrySet()) { sb.append(entry.getKey() + "=" + entry.getValue()); sb.append("&"); } String s = sb.toString(); if (s.endsWith("&")) { s = StringUtils.substringBeforeLast(s, "&"); } return s; } /*public static void test1(){ AppSecretKey askid = apiSignUtil.appSecretKeyService.getByAttr("askid", 1); System.out.println("askid = " + askid); }*/ /** * 生成签名 */ /*public static Map getSignature(Object param,String appid, String secretKey) { ObjectMapper objectMapper = new ObjectMapper(); Map params; try { String jsonStr = objectMapper.writeValueAsString(param); params = objectMapper.readValue(jsonStr, Map.class); } catch (Exception e) { throw new RuntimeException("生成签名:转换json失败"); } if (params.get(TIME_STAMP_KEY) == null) { params.put(TIME_STAMP_KEY, System.currentTimeMillis()); } //对map参数进行排序生成参数 Set<String> keysSet = params.keySet(); Object[] keys = keysSet.toArray(); Arrays.sort(keys); String temp = Arrays.stream(keys).map(key -> key + "=" + (!params.containsKey(key) ? "" : params.get(key))) .collect(Collectors.joining("&")); //根据参数生成签名 String sign = DigestUtils.sha256Hex(temp + appid + secretKey).toUpperCase();// params.put(SIGN_KEY, sign); return params; }*/ /** * 校验签名 */ /*public static boolean checkSignature(HttpServletRequest request,String appid, String secretKey) throws IOException { //获取request中的json参数转成map Map<String, Object> param = getAllParams(request); String sign = (String) param.get(SIGN_KEY); Long start = convertTimestamp(param.get(TIME_STAMP_KEY)); long now = System.currentTimeMillis(); //校验时间有效性 if (start == null || now - start > EXPIRE_TIME || start - now > 0L) { return false; } //是否携带签名 if (StringUtils.isBlank(sign)) { return false; } //获取除签名外的参数 param.remove(SIGN_KEY); //校验签名 Map paramMap = getSignature(param, appid,secretKey); String signature = (String) paramMap.get("sign"); if (sign.equals(signature)) { return true; } return false; }*/}