微信的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权限验证的签名了。
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