微信支付的签名算法

🔥 签名算法

签名生成的通用步骤如下:

  1. 第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特别注意以下重要规则:

  • 参数名ASCII码从小到大排序(字典序);
  • 如果参数的值为空不参与签名;
  • 参数名区分大小写;
  • 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
  • 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
  1. 第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。 注意:密钥的长度为32个字节
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ObjectUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * @author Wen先森
 * @version 1.0
 * @date 2022/8/25 11:07
 */
@Slf4j
public class SignatureUntils {
    public static final String  KEY="0de034fa56cf0ce676570d571de2705b";
    /**
     * 处理要签名的数据
     * 1. 获取参数content,content为json字符串
     * 2. 转换参数成URL 键值对的格式(即 key1=value1&key2=value2…)
     * 3. 返回整理好的待签名数据
     */
    private static String handleStr(Map<String,?> paramsMap){
        //转成map
        //获取参数名称转成List集合
        Set<String> keySet = paramsMap.keySet();
        List<String> paramNames = new ArrayList<String>(keySet);
        //对参数名称进行排序
        Collections.sort(paramNames);
        //把参数转化成url键值对格式并返回
        StringBuilder paramNameValue = new StringBuilder();
        for (String paramName : paramNames ) {
            if("sign".equals(paramName) || ObjectUtils.isEmpty(paramsMap.get(paramName))) {
                continue;
            }else{
                paramNameValue.append(paramName).append("=").append(paramsMap.get(paramName)).append("&");
            }
        }
       // paramNameValue.deleteCharAt(paramNameValue.length()-1);
        return paramNameValue.toString();
    }
    /**
     * 生成签名;
     *
     * @param params
     * @return
     */
    static public String signForInspiry(Map<String,?> params, String key) {
        //先排序
        String str = handleStr(params);
        StringBuffer sbkey = new StringBuffer(str);
        sbkey = sbkey.append("key=" + key);

        //MD5加密,结果转换为大写字符
        String sign = toMd5(sbkey.toString()).toUpperCase();
        return sign;
    }
    /**
     * 对字符串进行MD5加密
     *
     * @param str 需要加密的字符串
     * @return 小写MD5字符串 32位
     */
    public static String toMd5(String str) {
        String re = null;
        byte encrypt[];
        try {
            byte[] tem = str.getBytes();
            MessageDigest md5 = MessageDigest.getInstance("md5");
            md5.reset();
            md5.update(tem);
            encrypt = md5.digest();
            StringBuilder sb = new StringBuilder();
            for (byte t : encrypt) {
                String s = Integer.toHexString(t & 0xFF);
                if (s.length() == 1) {
                    s = "0" + s;
                }
                sb.append(s);
            }
            re = sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return re;
    }

    public static boolean checkSign(String sign,Map<String,?> params,String key){

        try {
            String signValue = signForInspiry(params, key);
            if (StringUtils.endsWithIgnoreCase(signValue,sign)){
                log.info("验签成功");
                return true;
            }
        } catch (Exception e) {
            log.info("验签异常");
            e.printStackTrace();
        }
        log.info("验签失败");
        return false;
    }
    public static void main(String[] args) {
        String sign="81AA2B818EAD40FE2D8E7E3242C14577";
        String key="0de034fa56cf0ce676570d571de2705b";
        Map<String,Object> map = new HashMap<>();
        map.put("deviceSn","000SD50030180000001");
        map.put("timestamp","1661759090226");
        map.put("sign",sign);
        map.put("orderNo","HMP2208310000584428263559179");
        // 需要签名参数
        System.out.println("签名参数:"+map);
        String sortPram = handleStr(map);
        // 排序后和去掉sign参数之后
        System.out.println("排序后参数:"+sortPram);
        String signValue = signForInspiry(map, "0de034fa56cf0ce676570d571de2705b");
        // MD5加密并全部大写
        System.out.println("签名内容:"+signValue);
        // 验签
        checkSign(sign, map, key);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,关于Java后台微信支付签名算法(MD5)的问题,我可以给您提供一些基本思路和代码实现: 首先,微信支付签名算法主要包含以下几步: 1. 将请求参数按照字典序排序,并拼接成字符串(参数值为空的不参与签名)。 2. 在拼接好的字符串后面加上商户支付密钥,并进行MD5运算,得到签名字符串。 3. 将签名字符串转换为大写字母形式后作为最终的签名值。 以下是Java代码实现: ```java import java.util.*; import java.security.*; import java.io.*; public class WechatPaySign { // 微信支付商户密钥 private static final String KEY = "your_mch_key"; // 微信支付签名算法(MD5) public static String sign(Map<String, String> params) { // 将参数按照字典序排序 List<String> keys = new ArrayList<String>(params.keySet()); Collections.sort(keys); // 拼接参数,不包括空值参数 StringBuilder sb = new StringBuilder(); for (String key : keys) { String value = params.get(key); if (value != null && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) { sb.append(key).append("=").append(value).append("&"); } } sb.append("key=").append(KEY); // 对拼接好的字符串进行MD5运算 String sign = null; try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] bytes = md.digest(sb.toString().getBytes("UTF-8")); sign = byteArrayToHexString(bytes); } catch (Exception e) { e.printStackTrace(); } return sign.toUpperCase(); } // 将字节数组转换为十六进制字符串 private static String byteArrayToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { String hex = Integer.toHexString(b & 0xFF); if (hex.length() == 1) { sb.append("0"); } sb.append(hex); } return sb.toString(); } } ``` 以上代码中,sign方法接收一个Map类型的参数,其中包含微信支付请求的各个参数,例如appid、mch_id、nonce_str、body、out_trade_no、total_fee、spbill_create_ip、notify_url等。在方法内部,首先将参数按照字典序排序,并将其拼接成字符串。然后,在拼接好的字符串后面加上商户支付密钥,并进行MD5运算,得到签名字符串。最后,将签名字符串转换为大写字母形式后作为最终的签名值。 需要注意的是,微信支付请求中的一些参数值需要根据实际情况进行编码或者加密,例如body参数需要进行UTF-8编码,而notify_url参数需要进行URL编码。此外,微信支付中还涉及到一些其他的安全问题,例如支付结果通知的验证、退款操作的安全等问题,需要开发者在实际开发中进行注意。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wen先森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值