微信JS-SDK获取signature签名以及config配置

微信的JS-SDK通过config接口注入权限验证配置,官网上的文档说的很清楚:

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名
    jsApiList: [] // 必填,需要使用的JS接口列表
});

上面的几个参数,对于像我这样子的初学者而言,不简单,所以在弄这块的时候没少碰钉子,这里说一下。

先说那个最烦人的signature,官网附录1是这么说的:

jsapi_ticket

生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。

1、获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):
http请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appID&secret=appsecret

2、用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,api 调用次数非常有限,频繁刷新api_ticket 会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

成功返回如下JSON:

{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}

获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。

签名算法
微信JS-SDK获取signature签名以及config配置_第1张图片
以上的东西加起来就是四步:

1、使用APPID和APPSecret获取access_token;

2、使用access_token获取jsapi_ticket ;

3、用时间戳、随机数、jsapi_ticket和要访问的url按照签名算法拼接字符串;

4、对第三步的字符串进行SHA1加密,得到签名。

第一步、获取access_token

public static String getAccessToken(String appId, String secret, String accessTokenUrl) {
        HttpClient client = HttpClients.createDefault();
        HttpGet get = new HttpGet(MessageFormat.format(accessTokenUrl,appId,secret));

        try {
            String accessToken = (String) CacheUtil.get("wxCache", "accessToken");;
            if (StringUtils.isBlank(accessToken) || StringUtils.isEmpty(accessToken)) {
                HttpResponse response = client.execute(get);
                HttpEntity entity = response.getEntity();
                String result = EntityUtils.toString(entity, "UTF-8");
                System.out.println(result);

                Map accessTokenMap = JSON.parseObject(result);
                accessToken = (String)accessTokenMap.get("access_token");

                CacheUtil.put("wxCache", "accessToken", accessToken);
            }
            return accessToken;
        } catch (ClientProtocolException e) {
            log.error(e.getMessage());
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        return  null;
    }

【注意】获取appID和appsecret,请参考博文:微信公众平台获取测试号的appID和appsecre

第二步、获取jsapi_ticket

public static String getTicket(String accessToken,String ticketUrl) {
        HttpClient client = HttpClients.createDefault();
        HttpGet get = new HttpGet(MessageFormat.format(ticketUrl,accessToken));

        try {
            String ticket = (String) CacheUtil.get("wxCache", "jsapi_ticket");
            if (StringUtils.isBlank(ticket) || StringUtils.isEmpty(ticket)) {
                HttpResponse response = client.execute(get);
                HttpEntity entity = response.getEntity();
                String result = EntityUtils.toString(entity, "UTF-8");
                System.out.println(result);

                Map jsApiTicketMap = JSON.parseObject(result);
                ticket = (String)jsApiTicketMap.get("ticket");

                CacheUtil.put("wxCache", "jsapi_ticket", ticket);
            }

            return ticket;
        } catch (ClientProtocolException e) {
            log.error(e.getMessage());
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        return null;
    }

拿到了jsapi_ticket之后就要参数名排序和拼接字符串,并加密了。以下为sha1的加密算法:

public static String sha1(String str){
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            digest.update(str.getBytes());
            byte messageDigest[] = digest.digest();
            // 创建 16进制字符串
            StringBuffer hexString = new StringBuffer();
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexString.append(0);
                }
                hexString.append(shaHex);
            }
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

获取签名:

	@Value("${wx.appId}")
    private String appId;

    @Value("${wx.secret}")
    private String secret;

    @Value("${wx.accessTokenUrl}")
    private String accessTokenUrl;

    @Value("${wx.ticketUrl}")
    private String ticketUrl;

	public ResponseData getWXConfigs(String pathUrl){
        //1.获取access_token  需要定时刷
        String accessToken = WeChatCommonUtil.getAccessToken(appId, secret, accessTokenUrl);
        if (accessToken == null){
            return new ErrorResponseData(500,"获取access_token失败");
        }

        //2.通过access_token获得ticket 需要定时刷新
        String ticket = WeChatCommonUtil.getTicket(accessToken,ticketUrl);
        if (ticket == null){
            return new ErrorResponseData(500,"获取ticket失败");
        }

        //3.时间戳和随机字符串
        String noncestr = WeChatCommonUtil.getNoncestr();
        String timestamp = WeChatCommonUtil.getTimestamp();

        System.out.println("accessToken:"+accessToken+"\njsapi_ticket:"+ticket+"\n时间戳:"+timestamp+"\n随机字符串:"+noncestr);
        log.info("accessToken:"+accessToken+"\njsapi_ticket:"+ticket+"\n时间戳:"+timestamp+"\n随机字符串:"+noncestr);

        //4、获取url
//        String url = WeChatCommonUtil.getUrl(pathUrl);
        String url = WeChatCommonUtil.getUrl(pathUrl);
        System.out.println(pathUrl);

        //5、将参数排序并拼接字符串
        String sortString = WeChatCommonUtil.sort(url, timestamp, ticket, noncestr);

        //6、将字符串进行sha1加密
        String signature = WeChatCommonUtil.sha1(sortString);

        System.out.println("url:"+url+"\nsortString:"+sortString+"\nsignature:"+signature);
        log.info("url:"+url+"\nsortString:"+sortString+"\nsignature:"+signature);

        Map map = Maps.newHashMap();
        map.put("appId",appId);
        map.put("timestamp",timestamp);
        map.put("nonceStr",noncestr);
        map.put("signature",signature);

        return new SuccessResponseData(map);
    }

参数的配置
在这里插入图片描述
【注意】WeChatCommonUtil完整工具类,请查看博文:WeChatCommonUtil完整工具类

该要的都有了,再次回到最开始的config配置,此时应该为:
js代码:

wx.config({  
    debug: true, //调试阶段建议开启  
    appId: "APPID",//APPID  
    timestamp: "timestamp",//上面main方法中拿到的时间戳timestamp  
    nonceStr: "nonceStr",//上面main方法中拿到的随机数nonceStr  
    signature: "signature",//上面main方法中拿到的签名signature  
    jsApiList: [  
           //所有要调用的 API 都要加到这个列表中  
          "chooseImage"//从本地的相册、图库选择图片  
    ]  
});  

以上的时间戳、随机数、签名一定要跟后台方法中获取到的一致,否则会报invalid signature错误。
另外,这个签名的有效时间为7200秒,也就是2个小时,因此当超过两个小时候,再访问也会报invalid signature错误。

另外还有一个错误:invalid url domain
这个跟生成签名时用的url有关系,官网的说法是:
invalid url domain当前页面所在域名与使用的appid没有绑定,请确认正确填写绑定的域名,如果使用了端口号,则配置的绑定域名也要加上端口号(一个appid可以绑定三个有效域名)

若是以上的配置没有问题,且dubug也设置为了true,那么再访问的时候,就会出现一个config:ok,这就说明配置成功了。

【注意】

安卓微信升级7.0后,小程序及公众号内 h5页面 jsapi定位(高德,百度,腾讯地图API)失败

调用失败原因

据说是 google 的安全策略问题, 涉及 隐私信息的 比如定位 需要 https 站点, 微信 7.0 更新了 sdk

解决方案

将网站/小程序/公众号后台地址从http 升级https ,而且必须是正规的SSL证书,自签名的证书 证书链不完整也是不行的。

比如我的公众号h5的域名地址是:http://weixin.xxx.cn,现在要升级为https://weixin.xxx.cn

注意:页面使用jssdk都需要使用https调用.

详细操作,请查看博文:小程序及公众号内 h5页面后台地址从http 升级https

你可能感兴趣的:(微信,js-sdk,signature,config)