前后端分离。前端实现参数签名,后端实现接口验签

首先是后台实现的接口验签,这里放上我的代码地址

贴上核心代码

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 + "&timestamp=" + timeStamp + "&" + param;
		} else {
			param = "appKey=" + appKey + "&timestamp=" + 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即可。

测试即可

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值