All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.bestwu.api.sign.ApiSignAlgorithm Maven / Gradle / Ivy

package cn.bestwu.api.sign;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.DigestUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 签名算法
 *
 * @author Peter Wu
 */
public class ApiSignAlgorithm {

  private static Logger log = LoggerFactory.getLogger(ApiSignAlgorithm.class);
  private final ApiSignProperties properties;

  protected ApiSignAlgorithm(ApiSignProperties properties) {
    this.properties = properties;
  }

  /**
   * 验证参数签名
   *
   * @param request 请求
   */
  public void checkSign(HttpServletRequest request) {
    String signParameter = properties.getSignParameter();
    String sign = request.getHeader(signParameter);
    if (sign == null) {
      sign = request.getParameter(signParameter);
    }

    if (skip(request)) {
      return;
    }
    if (!StringUtils.hasText(sign)) {
      if (log.isDebugEnabled()) {
        log.debug("客户端签名为空");
      }
      throw new InvalidRequestException();
    }
    if (sign.length() != 32) {
      if (log.isDebugEnabled()) {
        log.debug("客户端签名长度不匹配{}:{}", sign.length(), sign);
      }
      throw new InvalidRequestException();
    }
    String signParams = signParams().substring(0, 16);
    if (!sign.substring(0, 16).equalsIgnoreCase(signParams)) {
      if (log.isDebugEnabled()) {
        log.debug("客户端参数签名错误,客户端:{},服务端:{}", sign.substring(0, 16), signParams);
      }
      throw new InvalidRequestException();
    }
    if (properties.isUserAgent()) {
      String signUserAgent = signUserAgent().substring(16, 24);
      if (!sign.substring(16, 24).equalsIgnoreCase(signUserAgent)) {
        if (log.isDebugEnabled()) {
          log.debug("客户端UserAgent签名错误,客户端:{},服务端:{}", sign.substring(16, 24), signUserAgent);
        }
        throw new InvalidRequestException();
      }
    }

    int clientTimeDifference = properties.getClientTimeDifference();
    if (clientTimeDifference >= 0) {
      String signTime = sign.substring(24, 32);
      long time = System.currentTimeMillis() / (clientTimeDifference * 1000);
      if (!signTime(time).substring(24, 32).equalsIgnoreCase(signTime) && !signTime(time - 1)
          .substring(24, 32).equalsIgnoreCase(signTime) && !signTime(
          time + 1).substring(24, 32).equalsIgnoreCase(signTime)) {
        if (log.isDebugEnabled()) {
          log.debug("客户端时间签名错误,客户端:{}", sign.substring(24, 32));
        }
        throw new InvalidRequestException();
      }
    }

    if (log.isDebugEnabled()) {
      log.debug("签名验证通过");
    }
  }

  /**
   * 过滤签名验证
   */
  public static void skip() {
    getRequest().setAttribute("SKIP_SIGN", true);
  }

  /**
   * @param requestParams 请求参数
   * @return 签名
   */
  public String sign(MultiValueMap requestParams) {
    return signParams(requestParams) + signUserAgent() + signTime(
        System.currentTimeMillis() / properties.getClientTimeDifference());
  }

  /**
   * 签名时间
   *
   * @param time 时间
   * @return 签名后的时间
   */
  private String signTime(long time) {
    String timestamp = String.valueOf(time);
    timestamp += properties.getClient_secret();
    timestamp = DigestUtils.md5DigestAsHex(timestamp.getBytes());
    return timestamp;
  }

  /**
   * 签名 user-agent
   *
   * @return 签名后 user-agent
   */
  private String signUserAgent() {
    String userAgent = getRequest().getHeader("user-agent");
    if (userAgent == null) {
      userAgent = "";
    }
    userAgent += properties.getClient_secret();
    userAgent = DigestUtils.md5DigestAsHex(userAgent.getBytes());
    return userAgent;
  }

  /**
   * @return 签名后的参数
   */
  private String signParams() {
    Map requestParams = getRequest().getParameterMap();
    List keys = new ArrayList<>(requestParams.keySet());
    Collections.sort(keys);
    StringBuilder prestr = new StringBuilder("");
    for (String key : keys) {
      String[] values = requestParams.get(key);
      StringBuilder value = new StringBuilder();
      int length = values.length;
      for (int i = 0; i < length; i++) {
        value.append(values[i]);
        value.append((i == length - 1) ? "" : ",");
      }
      if (value == null || value.toString().equals("") || key.equalsIgnoreCase("sign")
          || key.equalsIgnoreCase("sign_type")) {
        continue;
      }
      prestr.append(key).append("=").append(value).append("&");
    }
    if (log.isDebugEnabled()) {
      log.debug("待签名参数字符串:{}", prestr);
    }
    prestr = prestr.append(properties.getClient_secret());
    return DigestUtils.md5DigestAsHex(prestr.toString().getBytes());
  }

  /**
   * @param requestParams 请求参数
   * @return 签名后的参数
   */
  private String signParams(MultiValueMap requestParams) {
    List keys = new ArrayList<>(requestParams.keySet());
    Collections.sort(keys);
    StringBuilder prestr = new StringBuilder("");
    for (String key : keys) {
      List values = requestParams.get(key);
      StringBuilder value = new StringBuilder();
      int length = values.size();
      for (int i = 0; i < length; i++) {
        value.append(values.get(i));
        value.append((i == length - 1) ? "" : ",");
      }
      if (value == null || value.toString().equals("") || key.equalsIgnoreCase("sign")
          || key.equalsIgnoreCase("sign_type")) {
        continue;
      }
      prestr.append(key).append("=").append(value).append("&");
    }
    if (log.isDebugEnabled()) {
      log.debug("待签名参数字符串:{}", prestr);
    }
    prestr = prestr.append(properties.getClient_secret());
    return DigestUtils.md5DigestAsHex(prestr.toString().getBytes());
  }


  /**
   * @param request 请求
   * @return request 是否跳过
   */
  private boolean skip(HttpServletRequest request) {
    if (properties.isCanSkip()) {
      Boolean skip_sign = (Boolean) request.getAttribute("SKIP_SIGN");
      return skip_sign == null ? false : skip_sign;
    } else {
      return false;
    }
  }

  /**
   * @return 当前请求
   */
  private static HttpServletRequest getRequest() {
    ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes();
    if (requestAttributes == null) {
      return null;
    }
    return requestAttributes.getRequest();
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy