SignatureUtil.java 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package com.railway.common.utils.sign;
  2. import static com.railway.common.core.domain.dto.ReturnCode.SIGN_CHECK_FAIL;
  3. import com.railway.common.core.domain.AjaxResult;
  4. import com.railway.common.core.domain.dto.ReturnCode;
  5. import com.railway.common.utils.DateUtils;
  6. import java.io.UnsupportedEncodingException;
  7. import java.net.URLEncoder;
  8. import java.security.InvalidKeyException;
  9. import java.security.NoSuchAlgorithmException;
  10. import java.time.LocalDateTime;
  11. import java.util.Arrays;
  12. import java.util.Map;
  13. import javax.crypto.Mac;
  14. import javax.crypto.spec.SecretKeySpec;
  15. import javax.xml.bind.DatatypeConverter;
  16. import lombok.extern.slf4j.Slf4j;
  17. import org.apache.commons.lang3.StringUtils;
  18. /**
  19. * 接口签名检查
  20. *
  21. * @author zhaomn
  22. */
  23. @Slf4j
  24. public class SignatureUtil {
  25. public static final String STR_TIMESTAMP = "timestamp";
  26. public static final String STR_SIGNATURE = "signature";
  27. public static final long MAX_TIME_DIFF = 600L;
  28. private static final String ENCODING = "UTF-8";
  29. private static final String HMAC_SHA256 = "HmacSHA256";
  30. public static String getParamString(Map<String, String> paramMap)
  31. throws UnsupportedEncodingException {
  32. if (paramMap == null || paramMap.isEmpty()) {
  33. return "";
  34. }
  35. // 对参数进行排序
  36. String[] sortedKeys = paramMap.keySet().toArray(new String[]{});
  37. Arrays.sort(sortedKeys);
  38. final String SEPARATOR = "&";
  39. // 生成stringToSign字符串
  40. StringBuilder stringToSign = new StringBuilder();
  41. StringBuilder canonicalizedQueryString = new StringBuilder();
  42. boolean isFirst = true;
  43. for (String key : sortedKeys) {
  44. if (isFirst) {
  45. isFirst = false;
  46. } else {
  47. canonicalizedQueryString.append(SEPARATOR);
  48. }
  49. // 这里注意对key和value进行编码
  50. canonicalizedQueryString.append(percentEncode(key)).append("=")
  51. .append(percentEncode(paramMap.get(key)));
  52. }
  53. // 这里注意对canonicalizedQueryString进行编码
  54. stringToSign.append(percentEncode(canonicalizedQueryString.substring(0)));
  55. return stringToSign.toString();
  56. }
  57. private static String percentEncode(String value) throws UnsupportedEncodingException {
  58. return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*",
  59. "%2A").replace("%7E", "~") : null;
  60. }
  61. public static AjaxResult checkTimestamp(String requestId, String userTimestamp){
  62. if (StringUtils.isBlank(userTimestamp)) {
  63. log.debug("checkSignature, missing parameters, requestId {}, timestamp {}",
  64. requestId, userTimestamp);
  65. return AjaxResult.error(ReturnCode.REQUIRED_PARAM_MISSING);
  66. }
  67. LocalDateTime urlDateTime = DateUtils.parseDateTime(userTimestamp);
  68. if (null == urlDateTime) {
  69. log.debug("checkSignature, time format error, requestId {}, timestamp {}",
  70. requestId, userTimestamp);
  71. return AjaxResult.error(ReturnCode.DATETIME_FORMAT_ERROR);
  72. }
  73. LocalDateTime now = LocalDateTime.now();
  74. if (urlDateTime.isAfter(now.plusSeconds(SignatureUtil.MAX_TIME_DIFF))
  75. || urlDateTime.isBefore(now.minusSeconds(SignatureUtil.MAX_TIME_DIFF))) {
  76. log.debug("checkSignature, time is shift too many, in {}, now {}", urlDateTime, now);
  77. return AjaxResult.error(ReturnCode.DATETIME_SHIFT_TOO_MANY);
  78. }
  79. return AjaxResult.success();
  80. }
  81. public static AjaxResult checkSignature(String requestId, String strToSign,
  82. String userSignature, String aesKey) {
  83. if (StringUtils.isBlank(strToSign)) {
  84. return AjaxResult.success();
  85. }
  86. if (StringUtils.isBlank(userSignature)) {
  87. log.debug("checkSignature, missing parameters, requestId {}", requestId);
  88. return AjaxResult.error(ReturnCode.REQUIRED_PARAM_MISSING);
  89. }
  90. String signature = createSignature(strToSign, aesKey);
  91. if (StringUtils.isEmpty(signature)) {
  92. log.debug("checkSignature, calc signature null {}", requestId);
  93. return AjaxResult.error(SIGN_CHECK_FAIL);
  94. }
  95. boolean check = signature.equals(userSignature);
  96. if (!check) {
  97. log.debug(
  98. "checkSignature, signature not equal, strToSign {}, user signature {}, calc signature {}",
  99. strToSign, userSignature, signature);
  100. return AjaxResult.error(SIGN_CHECK_FAIL);
  101. }
  102. return AjaxResult.success();
  103. }
  104. private static String createSignature(String strToSign, String key) {
  105. try {
  106. SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(ENCODING),
  107. SignatureUtil.HMAC_SHA256);
  108. Mac mac = Mac.getInstance(SignatureUtil.HMAC_SHA256);
  109. mac.init(signingKey);
  110. byte[] rawHmac = mac.doFinal(strToSign.getBytes(ENCODING));
  111. log.debug("printHexBinary= {}", DatatypeConverter.printHexBinary(rawHmac));
  112. log.debug("printBase64Binary= {}", DatatypeConverter.printBase64Binary(rawHmac));
  113. return DatatypeConverter.printBase64Binary(rawHmac);
  114. } catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException ignore) {
  115. }
  116. return null;
  117. }
  118. public static void main(String[] args) {
  119. createSignature(
  120. "code%3D12%26password%3DdB123456%26username%3D1088%26uuid%3Dacca0f11d8e2450e85fd45d76c49b951",
  121. "s#e@5f98H*^his%t");
  122. }
  123. }