• [微信]微信JS-SDK权限签名生成及验证



    在使用微信的分享、图片等众多功能时,通常需要在config接口注入权限验证配置,而配置里有需要我们的权限签名,这里简单说一下权限签名的生成和验证

    一、获取access_token

    获取access_token需要两个东西,appID和appsecret,测试账号在此申请即用
    在这里插入图片描述
    测试账号的access_token每天做多获取2000次,最好是缓存起来,避免获取次数过多达到上限,申请测试账号之后,拿到appID和appsecret访问下列地址即可获取

    https请求方式: GET
    https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

    获取access_token代码:

    public synchronized String getAccessToken() {
            Object redisToken = redisTemplate.opsForValue().get("accessToken");
            if (redisToken == null) {
                String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=" + "client_credential"
                        + "&appid=" + appId + "&secret=" + appSecret;
    
                // 获取accessToken
                String accessTokenBody = cn.hutool.http.HttpUtil.get(accessTokenUrl);
    
                log.info("获取accessToken{}", accessTokenBody);
    
                com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(accessTokenBody);
                String accessToken = null;
                try {
                    accessToken = (String) jsonObject.get("access_token");
                    log.info("accessToken:{}", accessToken);
                } catch (Exception e) {
                    log.error("获取accessToken异常");
                }
                // 存储一个小时
                redisTemplate.opsForValue().set("accessToken", accessToken, Constant.GenericNumber.NUMBER_ONE, TimeUnit.HOURS);
                return accessToken;
            } else {
                return redisToken.toString();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    二、获取jsapi_ticket

    使用第一步获取的access_token访问下述地址获取

    采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

    这一步也是需要进行缓存的,具体代码如下

    private synchronized String getTicket(String accessToken) {
    
            Object jsapiTicket = redisTemplate.opsForValue().get("jsapiTicket");
    
            if (jsapiTicket == null) {
                String getTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken
                        + "&type=jsapi";
    
                // 获取getTicketResult
                String getTicketResult = cn.hutool.http.HttpUtil.get(getTicketUrl);
                JSONObject ticketResultObject = JSONObject.parseObject(getTicketResult);
    
                String ticket = null;
                try {
                    ticket = (String) ticketResultObject.get("ticket");
                    log.info("ticket:{}", ticket);
                } catch (Exception e) {
                    log.error("获取ticket异常");
                }
    
                // 缓存中的accessToken可能不是最新的,导致获取ticket失败
                // 清除redis缓存的accessToken重新获取 不使用递归避免其他原因获取失败而重复调用
                if (ticket == null) {
                    redisTemplate.delete("accessToken");
                    return getTicket(accessToken);
                }
                return ticket;
    
            } else {
                return jsapiTicket.toString();
            }
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    三、拼接参数,SHA-1加密获取签名

    签名生成规则如下:

    参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳),url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用 URL 键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL
    转义。

    即signature=sha1(string1)。 示例:

    noncestr=Wm3WZYTPz0wzccnW
    jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
    timestamp=1414587457
    url=http://mp.weixin.qq.com?params=value

    注意!注意!注意!
    JAVA获取的时间戳是到毫秒级的,但是这里的时间戳是到秒的,需要换算之后才可以,生成之后的键值对一共是四组,不能有半组存在,尤其是开头的 “jsapi_ticket= ” 一定要有

    SHA-1加密工具类:

    private String encryptSHA(String signStr) {
            StringBuffer hexValue = new StringBuffer();
            MessageDigest sha = null;
            try {
                sha = MessageDigest.getInstance("SHA-1");
                byte[] byteArray = signStr.getBytes("UTF-8");
                byte[] md5Bytes = sha.digest(byteArray);
                for (int i = 0; i < md5Bytes.length; i++) {
                    int val = ((int) md5Bytes[i]) & 0xff;
                    if (val < 16) {
                        hexValue.append("0");
                    }
                    hexValue.append(Integer.toHexString(val));
                }
            } catch (Exception e) {
                e.printStackTrace();
                return "";
            }
    
            return hexValue.toString();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    获取签名代码:

    public cn.hutool.json.JSONObject createJsapiTicket(String url) {
            String accessToken = getAccessToken();
            String ticket = getTicket(accessToken);
            long timestamp = System.currentTimeMillis() / 1000;
            String noncestr = "letsschool";
    
            String signStr = new StringBuilder("jsapi_ticket=")
                    .append(ticket)
                    .append("&noncestr=")
                    .append(noncestr)
                    .append("×tamp=")
                    .append(timestamp)
                    .append("&url=")
                    .append(url)
                    .toString();
    
            log.info("signStr:{}", signStr);
    
            String signature = encryptSHA(signStr);
            cn.hutool.json.JSONObject returnJson = JSONUtil.createObj();
            returnJson.put("timestamp", timestamp);
            returnJson.put("ticket", ticket);
            returnJson.put("noncestr", noncestr);
            returnJson.put("signature", signature);
            returnJson.put("appId", appId);
    
            return returnJson;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    四、验证签名

    访问此地址,出现如下界面,输入参数生成签名,对比一致即可
    在这里插入图片描述

  • 相关阅读:
    为什么亿级数据量时要使用位图?位图和布隆过滤器有什么关系?
    java-net-php-python-net本科生毕业设计选导师系统演示录像2019计算机毕业设计程序
    IDEA自定义Maven仓库
    【MySQL架构篇】存储引擎
    Mac 远程 Ubuntu
    《2023中国企业数智化转型升级服务全景图/产业图谱2.0版》重磅发布
    Spark 中 Aggregate 的实现
    parsel的使用
    C/C++文档编辑器
    C#进阶09——值类型和引用类型2
  • 原文地址:https://blog.csdn.net/lkx021699/article/details/127664386