
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