1、新建Certificate类
package com.wise.medical.common.utils;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.*;
/**
* 实现开放API接口签名验证
* 参考链接:https://www.jianshu.com/p/ad410836587a
*/
public class Certificate {
public static Logger logger = LoggerFactory.getLogger(LoggerFactory.class);
/**
* Certificate构造对象,存储签名相关的参数
*/
private CertificateBuilder property;
/**
* 假设允许客户端和服务端最多能存在15分钟的时间差,同时追踪记录在服务端的nonce集合。
* 当有新的请求进入时,
* 首先检查携带的timestamp是否在15分钟内,如超出时间范围,则拒绝,
* 然后查询携带的nonce,如存在已有集合,则拒绝。否则,记录该nonce,并删除集合内时间戳大于15分钟的nonce
* (可以使用redis的expire,新增nonce的同时设置它的超时失效时间为15分钟)。
*/
private String timestamp;
/**
* 唯一的随机字符串,用来标识每个被签名的请求
*/
private String nonce;
/**
* 签名
*/
private String sign;
public Certificate(CertificateBuilder builder) {
this.property = builder;
}
/**
* 获取最终请求参数列表
* 注意:外部不要将timestamp、nonce、accessKey和sign这4个参数添加到方法参数params集合中
*/
public String getUrlParamsWithSign(final LinkedHashMap<String, String> params) {
this.sign = getSign(params);
//6、最终请求Url参数
params.put("timestamp", this.timestamp);
params.put("nonce", this.nonce);
params.put("sign", this.sign);
params.put("token", property.token);
List<String> urlParams = new ArrayList<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
String strParam = MessageFormat.format("{0}={1}", entry.getKey(), entry.getValue());
urlParams.add(strParam);
}
return String.join("&", urlParams);
}
/**
* 获取签名
* 注意:外部不要将timestamp、nonce、accessKey和sign这4个参数添加到方法参数params集合中
*/
public String getSign(final LinkedHashMap<String, String> params) {
if (this.sign == null || "".equals(this.sign))
{
this.sign = createSign(params);
}
return this.sign;
}
/**
* 创建签名
* 注意:外部不要将timestamp、nonce、accessKey和sign这4个参数添加到方法参数params集合中
*/
private String createSign(final LinkedHashMap<String, String> params) {
//1、除去空值请求参数
LinkedHashMap<