微信的JS-SDK通过config接口注入权限验证配置,官网上的文档说的很清楚:
1 2 3 4 5 6 7 8 | wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '',// 必填,签名,见附录1 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); |
上面的几个参数,对于像我这样子的初学者而言,不简单,所以在弄这块的时候没少碰钉子,这里说一下。
先说那个最烦人的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):../15/54ce45d8d30b6bf6758f68d2e95bc627.html
2、用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
成功返回如下JSON:
1 2 3 4 5 6 | { "errcode":0, "errmsg":"ok", "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA", "expires_in":7200 } |
获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。
签名算法
签名生成规则如下:参与签名的字段包括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
步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
步骤2. 对string1进行sha1签名,得到signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事项:
1、签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
2、签名用的url必须是调用JS接口页面的完整URL。
3、出于安全考虑,开发者必须在服务器端实现签名的逻辑。
————————————————————————————————————————————-
以上的东西加起来就是四步:
1、使用APPID和APPSecret获取access_token;
2、使用access_token获取jsapi_ticket ;
3、用时间戳、随机数、jsapi_ticket和要访问的url按照签名算法拼接字符串;
4、对第三步的字符串进行SHA1加密,得到签名。
实际接口模拟过程[以下接口可以直接在浏览器打开获取,请先设置好公众号的IP白名单和信任域名]:
一 提交appid和secret获取access_token
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wxaec507f9307e21fa&secret=98fc9b3084235045302aa2bc15232dbd
1 | {"access_token":"11_ClCjH9p7meWlam4UKCK0s1M6n-CvfSdl6GO1sENlOUWd7EWOJ-SYH8rE_FpkB2FUdRfSpsi4nJhEIjwghCFDh-KqtdFvy5hanet_gfjw8qrM9dfMsFDKoo0pw_le3WOoixtaewp_Qwct4LlABCJfAFAFGN","expires_in":7200} |
二 提交access_token获取ticket
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=11_ClCjH9p7meWlam4UKCK0s1M6n-CvfSdl6GO1sENlOUWd7EWOJ-SYH8rE_FpkB2FUdRfSpsi4nJhEIjwghCFDh-KqtdFvy5hanet_gfjw8qrM9dfMsFDKoo0pw_le3WOoixtaewp_Qwct4LlABCJfAFAFGN&type=jsapi
1 | {"errcode":0,"errmsg":"ok","ticket":"kgt8ON7yVITDhtdwci0qeYhlD32uHfZ66A8yFWUdiwqRwjUVzdRv_vCaO-xip5jp5aZkRda5_bDY_5YRVzjwsQ","expires_in":7200} |
三 按首字母顺序拼接4个参数
jsapi_ticket=kgt8ON7yVITDhtdwci0qeYhlD32uHfZ66A8yFWUdiwqRwjUVzdRv_vCaO-xip5jp5aZkRda5_bDY_5YRVzjwsQ&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=https://blog.dingxiaolin.com/demo/record
注意事项:noncestr和timestamp是随机字符,,url为引入JS-SDK页面的URL然后截取#之前的字符串
四 对以上的一串字符串进行SHA1加密
可以在一下页面进行在线加密:
http://tool.oschina.net/encrypt?type=2
或
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
对以上字符串sha1加密得到signature
ecc019287c41049b1b1f1a4966dc6a0e0496e9f3
这个签名的有效时间为7200秒,也就是2个小时,因此当超过两个小时候,再访问也会报invalid signature错误。
前端DEMO如下:
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> <meta name="viewport" content="width=640, user-scalable=no"> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <meta http-equiv="Expires" content="0"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="format-detection" content="telephone=no"> <meta name="apple-mobile-web-app-title" content=""> <title>录音test</title> <style type="text/css"> @charset "utf-8"; *{ margin:0px; padding:0px; box-sizing:border-box; -webkit-tap-highlight-color:rgba(0,0,0,0);} html{ max-width:640px; margin:0 auto;} body{ font-family:"PingFangSC-Regular","sans-serif","STHeitiSC-Light","微软雅黑","Microsoft YaHei"; font-size:24px; line-height:1.5em; color:#000; -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; touch-callout:none; } .start_btn , .play_btn , .send_btn{ width:250px; height:60px; line-height:60px; margin:20px auto; text-align:center; border:#eee solid 2px; cursor:pointer;} .start_btn_in , .stop_btn{ color:#f00; border:#f00 solid 2px;} </style> </head> <body> <div class="start_btn">按住不放即可录音</div> <div class="play_btn">点我播放</div> <div class="send_btn">点我保存</div> <script type="text/javascript" src="https://cdn.bootcss.com/jquery/1.11.2/jquery.min.js"></script> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> <script type="text/javascript"> wx.config({ debug: false, appId: 'wxaec507f9307e21fa ', timestamp: '1531559802', nonceStr: 'Wm3WZYTPz0wzccnW', signature: '03d60a3cfa946b3d8623cfeb2d00503493db494c', jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage','startRecord','stopRecord','onVoiceRecordEnd','playVoice','stopVoice','onVoicePlayEnd','uploadVoice'] }); wx.ready(function(){ //返回音频的本地ID var localId; //返回音频的服务器端ID var serverId; //录音计时,小于指定秒数(minTime = 10)则设置用户未录音 var startTime , endTime , minTime = 2; //***********************************// //开始录音 $('.start_btn').on('touchstart',function(e){ e.preventDefault(); var $this = $(this); $this.addClass('start_btn_in'); startTime = new Date().getTime(); //开始录音 wx.startRecord(); }); //***********************************// //停止录音接口 $('.start_btn').on('touchend', function(){ var $this = $(this); $this.removeClass('start_btn_in'); //停止录音接口 wx.stopRecord({ success: function (res) { localId = res.localId; } }); endTime = new Date().getTime(); alert((endTime - startTime) / 1000); if((endTime - startTime) / 1000 < minTime){ localId = ''; alert('录音少于' + minTime + '秒,录音失败,请重新录音'); } }); //监听录音自动停止接口 wx.onVoiceRecordEnd({ //录音时间超过一分钟没有停止的时候会执行 complete 回调 complete: function (res) { localId = res.localId; $('.start_btn').removeClass('start_btn_in'); } }); //***********************************// $('.play_btn').on('click',function(){ if(!localId){ alert('您还未录音,请录音后再点击播放'); return; } var $this = $(this); if($this.hasClass('stop_btn')){ $(this).removeClass('stop_btn').text('点我播放'); // //暂停播放接口 // wx.pauseVoice({ // //需要暂停的音频的本地ID,由 stopRecord 或 onVoiceRecordEnd 接口获得 // localId: localId // }); //停止播放接口 wx.stopVoice({ //需要停止的音频的本地ID,由 stopRecord 或 onVoiceRecordEnd 接口获得 localId: localId }); }else{ $this.addClass('stop_btn').text('点我停止'); //播放语音接口 wx.playVoice({ //需要播放的音频的本地ID,由 stopRecord 或 onVoiceRecordEnd 接口获得 localId: localId }); } }); //监听语音播放完毕接口 wx.onVoicePlayEnd({ //需要下载的音频的服务器端ID,由uploadVoice接口获得 serverId: localId, success: function (res) { $('.play_btn').removeClass('stop_btn').text('点我播放'); //返回音频的本地ID //localId = res.localId; } }); //***********************************// //上传语音接口 $('.send_btn').on('click',function(){ if(!localId){ alert('您还未录音,请录音后再保存'); return; } alert('上传语音,测试,并未提交保存'); return; //上传语音接口 wx.uploadVoice({ //需要上传的音频的本地ID,由 stopRecord 或 onVoiceRecordEnd 接口获得 localId: localId, //默认为1,显示进度提示 isShowProgressTips: 1, success: function (res) { //返回音频的服务器端ID serverId = res.serverId; } }); }); }); </script> </body> </html> |
膜拜