当前位置:   article > 正文

模拟微信支付通过appid、appsecret使用md5获取sign,实现接口验签_android 微信支付sign签名值

android 微信支付sign签名值

使用场景,在接口开发过程中,我们通常不能暴露一个接口给第三方随便调用,要对第三方发来参数进行校验,看是不是具有访问权限,在微信支付接口中也是这个道理,我们要开通微信支付,微信会提供给我们appid(公众账号ID)、mer_id(商户号),appsecret(密钥),然后通过字段拼接,获取签名,发送给微信,微信验证没有问题才会返回正确数据。

注意:MD5验签有两个作用

1. 保证数据在传输过程中不会丢失

2. 通过分配appid、appsecret保证签名只有授权用户可以访问通过

进入正题

第一步. MD5根据appid、appsecret、时间戳生成签名

首先分配参数appid、appsecret

appid自定义,appsecret通过uuid获取

appid:用户标识,每个用户有不同得appid

appsecret: 安全密钥,必须事先分配给接口提供方用于验签

第二步. 根据用户发来数据验签

直接上代码,签名验证公共类

  1. package com.lf.md5.util;
  2. import lombok.extern.slf4j.Slf4j;
  3. import java.security.MessageDigest;
  4. import java.util.*;
  5. /**
  6. * @Title:
  7. * @Package
  8. * @Description: 生成有序map,签名,验签
  9. * @author insistOn
  10. * @date 2020/3/422:03
  11. */
  12. @Slf4j
  13. public class MD5 {
  14. /**
  15. * 生成微信支付sign
  16. * @return
  17. */
  18. public static String createSign(SortedMap<String, String> params, String key){
  19. StringBuilder sb = new StringBuilder();
  20. Set<Map.Entry<String, String>> es = params.entrySet();
  21. Iterator<Map.Entry<String,String>> it = es.iterator();
  22. //生成 stringA="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";
  23. while (it.hasNext()){
  24. Map.Entry<String,String> entry = (Map.Entry<String,String>)it.next();
  25. String k = (String)entry.getKey();
  26. String v = (String)entry.getValue();
  27. if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)){
  28. sb.append(k+"="+v+"&");
  29. }
  30. }
  31. sb.append("key=").append(key);
  32. String sign = MD5(sb.toString()).toUpperCase();
  33. return sign;
  34. }
  35. /**
  36. * 校验签名
  37. * @param params
  38. * @param key
  39. * @return
  40. */
  41. public static boolean isCorrectSign(SortedMap<String, String> params, String key){
  42. String sign = createSign(params,key);
  43. String weixinPaySign = params.get("sign").toUpperCase();
  44. log.info("通过用户发送数据获取新签名:{}", sign);
  45. return weixinPaySign.equals(sign);
  46. }
  47. /**
  48. * 获取有序map
  49. * @param map
  50. * @return
  51. */
  52. public static SortedMap<String,String> getSortedMap(Map<String,String> map){
  53. SortedMap<String, String> sortedMap = new TreeMap<>();
  54. Iterator<String> it = map.keySet().iterator();
  55. while (it.hasNext()){
  56. String key = (String)it.next();
  57. String value = map.get(key);
  58. String temp = "";
  59. if( null != value){
  60. temp = value.trim();
  61. }
  62. sortedMap.put(key,temp);
  63. }
  64. return sortedMap;
  65. }
  66. /**
  67. * md5常用工具类
  68. * @param data
  69. * @return
  70. */
  71. public static String MD5(String data){
  72. try {
  73. MessageDigest md5 = MessageDigest.getInstance("MD5");
  74. byte [] array = md5.digest(data.getBytes("UTF-8"));
  75. StringBuilder sb = new StringBuilder();
  76. for (byte item : array) {
  77. sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
  78. }
  79. return sb.toString().toUpperCase();
  80. }catch (Exception e){
  81. e.printStackTrace();
  82. }
  83. return null;
  84. }
  85. }

获取签名测试类

  1. package com.lf.md5.util;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.junit.jupiter.api.Test;
  4. import java.util.Date;
  5. import java.util.SortedMap;
  6. import java.util.TreeMap;
  7. import static org.junit.jupiter.api.Assertions.*;
  8. /**
  9. * @author insistOn
  10. * @Title: 验签测试
  11. * @Package
  12. * @Description: 验签作用:
  13. * 1. 防注数据传输中被串改
  14. * 2. 指定appid、key、appsecret的用户才能访问接口
  15. * @date 2020/3/422:08
  16. */
  17. @Slf4j
  18. class MD5Test {
  19. /**
  20. * 实际项目使用需根据自己需要,提前分配appid和appsecret
  21. */
  22. // 随便定义一个值
  23. private static final String appid = "wx123456789";
  24. // 提前生成一个appsecret用于验签,CommonUtils.generateUUID()
  25. private static final String appsecret = "7214fefff0cf47d7950cb2fc3b5d670a";
  26. // 定义时间戳, 时间戳作用是防止接口被重复调用,真正使用时,可以验证当时间在20秒内可以访问,其他时间超时
  27. private static final String time = "1583332804914";
  28. // 把数据按照 首字母排序
  29. public static SortedMap<String, String> getData(){
  30. SortedMap<String, String> sortedMap = new TreeMap<>();
  31. sortedMap.put("str1", "某管理系统");
  32. sortedMap.put("appid", appid);
  33. sortedMap.put("timestamp", time);
  34. return sortedMap;
  35. }
  36. @Test
  37. void createSign() {
  38. // 模拟发送端根据appid等数据生成签名
  39. log.info("用户发送签名:{}", MD5.createSign(getData(), appsecret));
  40. }
  41. }

执行测试类,打印出签名为:

19:52:13.330 [main] INFO com.lf.md5.util.MD5Test - 用户发送签名:6646BFE4E9DD66FCC096B115230FA577

controller代码如下

  1. package com.lf.md5.controller;
  2. import com.lf.md5.util.MD5;
  3. import org.springframework.stereotype.Controller;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RequestParam;
  6. import org.springframework.web.bind.annotation.RestController;
  7. import java.util.Date;
  8. import java.util.SortedMap;
  9. import java.util.TreeMap;
  10. /**
  11. * @author insistOn
  12. * @Title:
  13. * @Package
  14. * @Description:
  15. * @date 2020/3/618:54
  16. */
  17. @RestController
  18. public class SignController {
  19. private static final String appsecret = "7214fefff0cf47d7950cb2fc3b5d670a";
  20. /**
  21. * 模拟验签
  22. * @param appid
  23. * @param timestamp
  24. * @param str1 你要穿的参数, 还有其他参数可继续加
  25. * @param sign 签名
  26. * @return
  27. */
  28. @RequestMapping("sign")
  29. public String checkSign(@RequestParam String appid,
  30. @RequestParam String timestamp,
  31. @RequestParam String str1,
  32. @RequestParam String sign){
  33. // 1. 校验时间戳
  34. long t = Long.valueOf(timestamp);
  35. // 时间查过20秒,则认为接口为重复调用,返回错误信息
  36. Date date = new Date();
  37. long nowtime = date.getTime();
  38. int seconds = (int) ((nowtime - t)/1000);
  39. // if(seconds > 20)
  40. // return "接口不允许重复访问!";
  41. // 2. 组装参数
  42. SortedMap<String, String> sortedMap = new TreeMap<>();
  43. sortedMap.put("str1", str1);
  44. sortedMap.put("appid", appid);
  45. sortedMap.put("timestamp", timestamp);
  46. sortedMap.put("sign", sign);
  47. // 3. 校验签名
  48. Boolean flag = MD5.isCorrectSign(sortedMap, appsecret);
  49. return flag? "签名验证通过" : "签名验证未通过";
  50. }
  51. }

注释掉验证时间戳代码,调用验签接口,postman输入以下链接,查看返回信息:

开启时间戳代码,测试时间大于20秒,则不允许访问,返回值如下

结尾:有兴趣的化,可以把appid等信息放数据库,对字段进行单个校验,同时支持多个appid等配置。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/258460
推荐阅读
相关标签
  

闽ICP备14008679号