首先是后台实现的接口验签,这里放上我的代码地址
贴上核心代码
public class SignUtil {
private static final String FIELD_SIGN = "sign";
private static final String FIELD_SIGN_TYPE = "sign_type";
private static final String TIMESTAMP = "timestamp";
private static final String APP_KEY = "appKey";
/**
* 默认超时时间
*/
private static final Long DEFAULT_TIME_OUT = 5000L;
private static String md5(String data) {
return SecureUtil.md5(data);
}
private static String hmacSha256(String data, String key) {
return SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(data, CharsetUtil.UTF_8);
}
/**
* 构建签名 Map
*
* @param appKey appKey
* @param appSecret appSecret
* @param signType {@link SignType} 签名类型
* @param haveSignType 签名是否包含 sign_type 字段
* @return 构建签名后的 Map
*/
public static Map<String, String> createSign(Map<String, String> params, String appKey, String appSecret, SignType signType, boolean haveSignType) {
return buildSign(params, appKey, appSecret, signType, haveSignType);
}
/**
* 构建签名
*
* @param params 需要签名的参数
* @param appKey appKey
* @param appSecret 密钥
* @param signType 签名类型
* @param haveSignType 签名是否包含 sign_type 字段
* @return 签名后的 Map
*/
private static Map<String, String> buildSign(Map<String, String> params, String appKey, String appSecret, SignType signType, boolean haveSignType) {
if (haveSignType) {
params.put(FIELD_SIGN_TYPE, signType.getType());
}
params.put(APP_KEY, appKey);
params.put(TIMESTAMP, String.valueOf(System.currentTimeMillis()));
String sign = createSign(params, appSecret, signType);
params.put(FIELD_SIGN, sign);
return params;
}
/**
* 生成签名
*
* @param params 需要签名的参数
* @param appSecret 密钥
* @param signType 签名类型
* @return 签名后的数据
*/
private static String createSign(Map<String, String> params, String appSecret, SignType signType) {
if (signType == null) {
signType = SignType.MD5;
}
// 生成签名前先去除sign
params.remove(FIELD_SIGN);
String tempStr = createLinkString(params);
String stringSignTemp = tempStr + "&key=" + appSecret;
if (signType == SignType.MD5) {
return md5(stringSignTemp).toUpperCase();
} else {
return hmacSha256(stringSignTemp, appSecret).toUpperCase();
}
}
/**
* 把所有元素排序
*
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
private static String createLinkString(Map<String, String> params) {
return createLinkString(params, false);
}
/**
* @param params 需要排序并参与字符拼接的参数组
* @param encode 是否进行URLEncoder
* @return 拼接后字符串
*/
private static String createLinkString(Map<String, String> params, boolean encode) {
return createLinkString(params, "&", encode);
}
/**
* @param params 需要排序并参与字符拼接的参数组
* @param connStr 连接符号
* @param encode 是否进行URLEncoder
* @return 拼接后字符串
*/
private static String createLinkString(Map<String, String> params, String connStr, boolean encode) {
return createLinkString(params, connStr, encode, false);
}
private static String createLinkString(Map<String, String> params, String connStr, boolean encode, boolean quotes) {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
StringBuilder content = new StringBuilder();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
// 拼接时,不包括最后一个&字符
if (i == keys.size() - 1) {
if (quotes) {
content.append(key).append("=").append('"').append(encode ? urlEncode(value) : value).append('"');
} else {
content.append(key).append("=").append(encode ? urlEncode(value) : value);
}
} else {
if (quotes) {
content.append(key).append("=").append('"').append(encode ? urlEncode(value) : value).append('"').append(connStr);
} else {
content.append(key).append("=").append(encode ? urlEncode(value) : value).append(connStr);
}
}
}
return content.toString();
}
/**
* URL 编码
*
* @param src 需要编码的字符串
* @return 编码后的字符串
*/
private static String urlEncode(String src) {
try {
return URLEncoder.encode(src, CharsetUtil.UTF_8).replace("+", "%20");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
//验签
/**
* 校验 sign
*
* @param params 参数
* @param appSecret appSecret
* @param signType {@link SignType}
* @return {@link Boolean} 验证签名结果
*/
public static boolean verifyNotify(Map<String, String> params, String appSecret, SignType signType) {
String sign = params.get("sign");
String localSign = createSign(params, appSecret, signType);
return sign.equals(localSign);
}
/**
* 验签 签名 自带默认验签超时时间默认5s
*
* @param params 参数
* @param appSecret secret
* @param signType {@link SignType}
* @return {@link Boolean} 验证签名结果
*/
public static boolean verifyTimeStampNotify(Map<String, String> params, String appSecret, SignType signType) {
return verifyTimeStampNotify(params, appSecret, signType, DEFAULT_TIME_OUT);
}
/**
* 验签 签名
*
* @param params 参数
* @param appSecret secret
* @param signType {@link SignType}
* @param timeout 超时时间
* @return {@link Boolean} 验证签名结果
*/
public static boolean verifyTimeStampNotify(Map<String, String> params, String appSecret, SignType signType, long timeout) {
String timeStamp = params.get(TIMESTAMP);
Assert.notNull(timeStamp, "{}不能为空", TIMESTAMP);
Assert.state(System.currentTimeMillis() - Long.parseLong(timeStamp) < timeout, "签名过期");
return verifyNotify(params, appSecret, signType);
}
前台js代码,这里用到的md5等代码,自己百度去找一个插件即可
getSign(obj) {
let that = this;
let param = obj
var timeStamp = new Date().getTime();
if (typeof param == "object") {
if (param != null && param != undefined && param != '') {
var arr = [];
for (var i in param) {
arr.push(i + "=" + param[i]);
}
param = arr.join("&")
}
}
// 判断是否有参数
if (param != null && param != 'undefined' && param != '') {
param = "appKey=" + appKey + "×tamp=" + timeStamp + "&" + param;
} else {
param = "appKey=" + appKey + "×tamp=" + timeStamp
}
var paramt = param.split("&");
param = paramt.sort().join("&");
var sign = md5(param + "&key=" + appSecret);
var ssss = param + "&sign=" + sign;
// console.log(ssss)
var ti = {};
var keyvalue = [];
var key = "",
value = ""
var paraString = ssss.split("&")
for (var i in paraString) {
keyvalue = paraString[i].split("=");
key = keyvalue[0];
value = keyvalue[1];
ti[key] = value;
}
return ti;
},
注意这里js生成的sign签名并没有转大写,后台验签的时候直接加上toUpperCase即可。
测试即可