微信JS-SDK说明文档
微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。
通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫等微信特有的能力,为微信用户提供更优质的网页体验。
此文档面向网页开发者介绍微信JS-SDK如何使用及相关注意事项。
在使用微信JS-SDK对应的JS接口前,需确保已获得使用对应JS接口的权限,可在下表中根据自己的帐号类型查看。 企业号帐号类型分为注册号和认证号,其中认证号拥有更多的JS-SDK权限,具体详见下方表格:
功能 | 接口 | 认证号 | 注册号 |
---|---|---|---|
基础接口 | 判断当前客户端版本是否支持指定JS接口 | 有 | 有 |
企业号 | 创建企业会话 | 有 | 有 |
打开企业通讯录选人 | 有 | 有 | |
分享接口 | 获取“分享到朋友圈”按钮点击状态及设置分享内容接口 | 有 | 无 |
获取“分享给朋友”按钮点击状态及设置分享内容接口 | 有 | 无 | |
获取“分享到QQ”按钮点击状态及设置分享内容接口 | 有 | 无 | |
获取“分享到腾讯微博”按钮点击状态及设置分享内容接 | 有 | 无 | |
图像接口 | 本地选图或拍照接口 | 有 | 有 |
图片预览接口 | 有 | 有 | |
上传图片接口 | 有 | 有 | |
下载图片接口 | 有 | 有 | |
音频接口 | 开始录音接口 | 有 | 有 |
停止录音接口 | 有 | 有 | |
播放音频接口 | 有 | 有 | |
暂停播放接口 | 有 | 有 | |
停止播放接口 | 有 | 有 | |
上传语音接口 | 有 | 有 | |
下载语音接口 | 有 | 有 | |
智能接口 | 识别音频并返回识别结果接口 | 有 | 有 |
设备信息 | 获取网络状态接口 | 有 | 有 |
地理位置 | 查看地理位置地图接口 | 有 | 有 |
获取地理位置接口 | 有 | 有 | |
界面操作 | 隐藏右上角菜单接口 | 有 | 有 |
显示右上角菜单接口 | 有 | 有 | |
关闭当前窗口接口 | 有 | 有 | |
批量隐藏菜单项接口 | 有 | 有 | |
批量显示菜单项接口 | 有 | 有 | |
隐藏所有非基本菜单项接口 | 有 | 有 | |
显示所有被隐藏的非基本菜单项接口 | 有 | 有 | |
微信扫一扫 | 扫一扫接口 | 有 | 有 |
注意: 所有的JS接口只能在企业号应用的可信域名下调用(包括子域名),可在企业号应用中心里设置应用可信域名。
步骤一:引入JS文件
在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js
备注:支持使用 AMD/CMD 标准模块加载方法加载
步骤二:通过config接口注入权限验证配置
所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。
wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', // 必填,企业号的唯一标识,此处填写企业号corpid timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '',// 必填,签名,见附录1 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });
步骤三:通过ready接口处理成功验证
wx.ready(function(){ // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。 });
步骤四:通过error接口处理失败验证
wx.error(function(res){ // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 });
所有接口通过wx对象(也可使用jWeixin对象)来调用,参数是一个对象,除了每个接口本身需要传的参数之外,还有以下通用参数:
注意:不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回。
以上几个函数都带有一个参数,类型为对象,其中除了每个接口本身返回的数据之外,还有一个通用属性errMsg,其值格式如下:
wx.checkJsApi({ jsApiList: ['chooseImage'] // 需要检测的JS接口列表,所有JS接口列表见附录2, success: function(res) { // 以键值对的形式返回,可用的api值true,不可用为false // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"} });
备注:checkJsApi接口是客户端6.0.2新引入的一个预留接口,第一期开放的接口均可不使用checkJsApi来检测。
企业号接口为企业号应用专有的JS-SDK接口
wx.openEnterpriseChat({ userIds: 'zhangshan;lisi;wangwu', // 必填,参与会话的成员列表。格式为userid1;userid2;...,用分号隔开,最大限制为2000个。userid单个时为单聊,多个时为群聊。 groupName: 'openEnterpriseChat讨论组', // 必填,会话名称。单聊时该参数传入空字符串""即可。 success: function(res) { // 回调 }, fail: function(res) { if(res.errMsg.indexOf('function not exist') > -1){ alert('版本过低请升级') } } });
注意:该JS-SDK需要验证企业号管理组权限,请参考:附录2-企业号管理组权限验证方法
var evalWXjsApi = function(jsApiFun) { if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") { jsApiFun(); } else { document.attachEvent && document.attachEvent("WeixinJSBridgeReady", jsApiFun); document.addEventListener && document.addEventListener("WeixinJSBridgeReady", jsApiFun); } } document.querySelector('#openEnterpriseContact_invoke').onclick = function() { evalWXjsApi(function() { WeixinJSBridge.invoke("openEnterpriseContact", { "groupId": "g50a5axxxx91706a", // 必填,管理组权限验证步骤1返回的group_id "timestamp": "1447334894", // 必填,管理组权限验证步骤2使用的时间戳 "nonceStr": "Wm3WZYTPz0wzccnW", // 必填,管理组权限验证步骤2使用的随机字符串 "signature": "f9afc6f80a0c81xxxxxxxxxxxxedff5001878", // 必填,管理组权限验证步骤2生成的签名 "params" : { 'departmentIds' : [1], // 非必填,可选部门ID列表(如果ID为0,表示可选管理组权限下所有部门) 'tagIds' : [1], // 非必填,可选标签ID列表(如果ID为0,表示可选所有标签) 'userIds' : ['zhangsan','lisi'], // 非必填,可选用户ID列表 'mode' : 'single', // 必填,选择模式,single表示单选,multi表示多选 'type' : ['department','tag','user'], // 必填,选择限制类型,指定department、tag、user中的一个或者多个 'selectedDepartmentIds' : [], // 非必填,已选部门ID列表 'selectedTagIds' : [], // 非必填,已选标签ID列表 'selectedUserIds' : [], // 非必填,已选用户ID列表 }, }, function(res) { if (res.err_msg.indexOf('function_not_exist') > -1) { alert('版本过低请升级'); } else if (res.err_msg.indexOf('openEnterpriseContact:fail') > -1) { return; } var result = JSON.parse(res.result); // 返回字符串,开发者需自行调用JSON.parse解析 var selectAll = result.selectAll; // 是否全选(如果是,其余结果不再填充) if (!selectAll) { var selectedDepartmentList = result.departmentList; // 已选的部门列表 for (var i = 0; i < selectedDepartmentList.length; i++) { var department = selectedDepartmentList[i]; var departmentId = department.id; // 已选的单个部门ID var departemntName = department.name; // 已选的单个部门名称 } var selectedTagList = result.tagList; // 已选的标签列表 for (var i = 0; i < selectedTagList.length; i++) { var tag = selectedTagList[i]; var tagId = tag.id; // 已选的单个标签ID var tagName = tag.name; // 已选的单个标签名称 } var selectedUserList = result.userList; // 已选的成员列表 for (var i = 0; i < selectedUserList.length; i++) { var user = selectedUserList[i]; var userId = user.id; // 已选的单个成员ID var userName = user.name; // 已选的单个成员名称 } } }) }); }
注意:该JS-SDK仅适用于从应用的“关联到会话”入口进入的网页
var evalWXjsApi = function(jsApiFun) { if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") { jsApiFun(); } else { document.attachEvent && document.attachEvent("WeixinJSBridgeReady", jsApiFun); document.addEventListener && document.addEventListener("WeixinJSBridgeReady", jsApiFun); } } // 发送文本消息 document.querySelector('#sendEnterpriseChat_text_invoke').onclick = function() { evalWXjsApi(function() { WeixinJSBridge.invoke("sendEnterpriseChat", { "type": "text", // 必填,text表示发送的内容是文字 "data": { "content": "text sent to enterprise chat", // 必填,表示发送的文字内容 } }, function(res) { alert(JSON.stringify(res)); }) }); } // 发送链接消息 document.querySelector('#sendEnterpriseChat_link_invoke').onclick = function() { evalWXjsApi(function() { WeixinJSBridge.invoke("sendEnterpriseChat", { "type": "link", // 必填,link表示发送的内容是链接 "data": { "imgUrl": "http://shp.qpic.cn/bizmp/PiajxSqBRaEJ60dDSjCqczZFTTHsyX5MvxibUq1L3jwokHORAYOV0OdQ/", // 必填,表示消息的图标 "title": "test title", // 非必填,但与desc不能同时为空 "desc": "test desc", // 非必填,但与title不能同时为空 "link": "http://qy.weixin.qq.com", // 必填,表示消息的链接 } }, function(res) { alert(JSON.stringify(res)); }) }); }
请注意不要有诱导分享等违规行为,对于诱导分享行为将永久回收企业号接口权限,详细规则请查看:朋友圈管理常见问题 。
wx.onMenuShareTimeline({ title: '', // 分享标题 link: '', // 分享链接,该链接域名必须与当前企业的可信域名一致 imgUrl: '', // 分享图标 success: function () { // 用户确认分享后执行的回调函数 }, cancel: function () { // 用户取消分享后执行的回调函数 } });
wx.onMenuShareAppMessage({ title: '', // 分享标题 desc: '', // 分享描述 link: '', // 分享链接,该链接域名必须与当前企业的可信域名一致 imgUrl: '', // 分享图标 type: '', // 分享类型,music、video或link,不填默认为link dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空 success: function () { // 用户确认分享后执行的回调函数 }, cancel: function () { // 用户取消分享后执行的回调函数 } });
wx.onMenuShareQQ({ title: '', // 分享标题 desc: '', // 分享描述 link: '', // 分享链接 imgUrl: '', // 分享图标 success: function () { // 用户确认分享后执行的回调函数 }, cancel: function () { // 用户取消分享后执行的回调函数 } });
wx.onMenuShareWeibo({ title: '', // 分享标题 desc: '', // 分享描述 link: '', // 分享链接 imgUrl: '', // 分享图标 success: function () { // 用户确认分享后执行的回调函数 }, cancel: function () { // 用户取消分享后执行的回调函数 } });
wx.onMenuShareQZone({ title: '', // 分享标题 desc: '', // 分享描述 link: '', // 分享链接 imgUrl: '', // 分享图标 success: function () { // 用户确认分享后执行的回调函数 }, cancel: function () { // 用户取消分享后执行的回调函数 } });
wx.chooseImage({ count: 1, // 默认9 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function (res) { var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片 } });
wx.previewImage({ current: '', // 当前显示图片的http链接 urls: [] // 需要预览的图片http链接列表 });
wx.uploadImage({ localId: '', // 需要上传的图片的本地ID,由chooseImage接口获得 isShowProgressTips: 1// 默认为1,显示进度提示 success: function (res) { var serverId = res.serverId; // 返回图片的服务器端ID } });
备注:上传图片有效期3天,可用微信多媒体接口下载图片到自己的服务器,此处获得的 serverId 即 media_id,参考文档
wx.downloadImage({ serverId: '', // 需要下载的图片的服务器端ID,由uploadImage接口获得 isShowProgressTips: 1// 默认为1,显示进度提示 success: function (res) { var localId = res.localId; // 返回图片下载后的本地ID } });
wx.startRecord();
wx.stopRecord({ success: function (res) { var localId = res.localId; } });
wx.onVoiceRecordEnd({ // 录音时间超过一分钟没有停止的时候会执行 complete 回调 complete: function (res) { var localId = res.localId; } });
wx.playVoice({ localId: '' // 需要播放的音频的本地ID,由stopRecord接口获得 });
wx.pauseVoice({ localId: '' // 需要暂停的音频的本地ID,由stopRecord接口获得 });
wx.stopVoice({ localId: '' // 需要停止的音频的本地ID,由stopRecord接口获得 });
wx.onVoicePlayEnd({ success: function (res) { var localId = res.localId; // 返回音频的本地ID } });
wx.uploadVoice({ localId: '', // 需要上传的音频的本地ID,由stopRecord接口获得 isShowProgressTips: 1// 默认为1,显示进度提示 success: function (res) { var serverId = res.serverId; // 返回音频的服务器端ID } });
备注: 上传语音有效期3天,可用企业号多媒体接口下载语音到自己的服务器,此处获得的 serverId 即 media_id,参考文档
wx.downloadVoice({ serverId: '', // 需要下载的音频的服务器端ID,由uploadVoice接口获得 isShowProgressTips: 1// 默认为1,显示进度提示 success: function (res) { var localId = res.localId; // 返回音频的本地ID } });
wx.translateVoice({ localId: '', // 需要识别的音频的本地Id,由录音相关接口获得 isShowProgressTips: 1, // 默认为1,显示进度提示 success: function (res) { alert(res.translateResult); // 语音识别的结果 } });
wx.getNetworkType({ success: function (res) { var networkType = res.networkType; // 返回网络类型2g,3g,4g,wifi } });
wx.openLocation({ latitude: 0, // 纬度,浮点数,范围为90 ~ -90 longitude: 0, // 经度,浮点数,范围为180 ~ -180。 name: '', // 位置名 address: '', // 地址详情说明 scale: 1, // 地图缩放级别,整形值,范围从1~28。默认为最大 infoUrl: '' // 在查看位置界面底部显示的超链接,可点击跳转 });
wx.getLocation({ type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' success: function (res) { var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 var longitude = res.longitude ; // 经度,浮点数,范围为180 ~ -180。 var speed = res.speed; // 速度,以米/每秒计 var accuracy = res.accuracy; // 位置精度 } });
wx.hideOptionMenu();
wx.showOptionMenu();
wx.closeWindow();
wx.hideMenuItems({ menuList: [] // 要隐藏的菜单项,所有menu项见附录3 });
wx.showMenuItems({ menuList: [] // 要显示的菜单项,所有menu项见附录3 });
wx.hideAllNonBaseMenuItem();
wx.showAllNonBaseMenuItem();
wx.scanQRCode({ desc: 'scanQRCode desc', needResult: 0, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果, scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有 success: function (res) { // 回调 } error: function(res){ if(res.errMsg.indexOf('function_not_exist') > 0){ alert('版本过低请升级') } } });
微信卡券接口中使用的签名凭证api_ticket,与步骤二中config使用的签名凭证jsapi_ticket不同,开发者在调用微信卡券JS-SDK的过程中需依次完成两次不同的签名,并确保凭证的缓存。
api_ticket 是用于调用微信卡券JS API的临时票据,有效期为7200 秒,通过access_token 来获取。
开发者注意事项:
1.此用于卡券接口签名的api_ticket与步骤三中通过config接口注入权限验证配置使用的jsapi_ticket不同。
2.由于获取api_ticket 的api 调用次数非常有限,频繁刷新api_ticket 会导致api调用受限,影响自身业务,开发者需在自己的服务存储与更新api_ticket。
Https请求方式:GET
https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token=ACCESS_TOKEN&type=wx_card
参数 | 必须 | 说明 |
---|---|---|
access_token | 是 | 调用接口凭证 |
type | 是 | 此处固定为wx_card |
{ "errcode":0, "errmsg":"ok", "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKdvsdshFKA", "expires_in":7200 }
参数 | 说明 |
---|---|
errcode | 错误码 |
errmsg | 错误信息 |
ticket | api_ticket,卡券接口中签名所需凭证 |
expires_in | 有效时间 |
wx.chooseCard({ shopId: '', // 门店Id cardType: '', // 卡券类型 cardId: '', // 卡券Id timestamp: 0, // 卡券签名时间戳 nonceStr: '', // 卡券签名随机串 signType: '', // 签名方式,默认'SHA1' cardSign: '', // 卡券签名 success: function (res) { var cardList= res.cardList; // 用户选中的卡券列表信息 } });
参数 | 必须 | 说明 |
---|---|---|
shopId | 否 | 门店ID。shopID用于筛选出拉起带有指定location_list(shopID)的卡券列表,非必填,企业号暂不支持。 |
cardType | 否 | 卡券类型,用于拉起指定卡券类型的卡券列表。当cardType为空时,默认拉起所有卡券的列表,非必填。 |
cardId | 否 | 卡券ID,用于拉起指定cardId的卡券列表,当cardId为空时,默认拉起所有卡券的列表,非必填。 |
timestamp | 是 | 时间戳。 |
nonceStr | 是 | 随机字符串。 |
signType | 是 | 签名方式,目前仅支持SHA1 |
cardSign | 是 | 签名。 |
cardSign详见附录5。开发者特别注意:签名错误会导致拉取卡券列表异常为空,请仔细检查参与签名的参数有效性。
特别提醒 拉取列表仅与用户本地卡券有关,拉起列表异常为空的情况通常有三种:签名错误、时间戳无效、筛选机制有误。请开发者依次排查定位原因。
wx.addCard({ cardList: [{ cardId: '', cardExt: '' }], // 需要添加的卡券列表 success: function (res) { var cardList = res.cardList; // 添加的卡券列表信息 } });
cardExt详见附录5,值得注意的是,这里的card_ext参数必须与参与签名的参数一致,格式为字符串而不是Object,否则会报签名错误。
wx.openCard({ cardList: [{ cardId: '', code: : '' }], // // 需要打开的卡券列表 });
使用场景:开发者调用该接口获取本机支持的SOTER生物认证方式,以便确定所开发功能是否可用,以及确定使用何种方式进行SOTER生物识别(兼容版本:ios/android 6.3.16及以上版本)
wx.config({ beta:true, }); wx.ready(function () { wx.invoke("getSupportSoter", {},function(res){ var ret = " support_mode: " + res.support_mode; alert(ret); }); });
参数 | 说明 |
---|---|
support_mode | 该设备支持的可被SOTER识别的生物识别方式,十六进制无浮点整数。生物识别方式定义如表1(持续更新中) |
err_msg | 本地生物识别结果的错误信息 |
表1:生物识别方式定义
生物识别方式 | 十六进制定义 |
---|---|
指纹识别 | 0x1 |
例如:该设备不支持SOTER或者不具备任何被SOTER支持的生物识别方式,则返回0x0;该设备支持SOTER方案指纹识别接口,则返回0x1;该设备同时支持SOTER方案指纹和人脸识别接口,则返回0x3 (0x1 | 0x2);以此类推
使用场景:开发者调用该接口使用给定的生物认证方式进行符合SOTER规范的可信鉴权
wx.config({ beta:true, }); wx.ready(function () { wx.invoke("requireSoterBiometricAuthentication", {"auth_mode": 0xff, "challenge": "sample_challenge", "auth_content": "请将使用指纹识别"},function(res){ if(res.errCode == 0) { //检查use_mode //使用result_json和result_son_signature本地验签是否合法 //使用所提供的后台接口将result_json和result_son_signature发送到微信企业号后台进行验签 //处理验签结果 } else { var ret = res.err_msg; ret += " errCode: " + res.resultCode; alert(ret); } }); });
参数 | 必须 | 说明 |
---|---|---|
auth_mode | 是 | 生物识别方式(注1) |
challege | 是 | 挑战因子(注2) |
auth_content | 否 | 验证描述,即识别过程中显示在界面上的对话框提示内容。 |
{ "err_code":0, "err_msg":"ok", "use_mode":"bxLdikRXVbTPdHSM05e5u5sUoXNKdvsdshFKA", "result_json":"$RESULRTJSON", "result_json_signature":"$RESULRTJSONSIGNATURE", }
参数 | 说明 |
---|---|
err_code | 本地生物识别结果(错误码见表3) |
err_msg | 本地生物识别结果的错误信息 |
use_mode | 所使用的生物识别方式(定义见表1) |
result_json | 在设备安全区域(TEE)内获得的本机安全信息(如TEE名称版本号等以及防重放参数)以及本次认证信息(仅Android支持,本次认证的指纹ID)(注3) |
result_json_signature | 使用SOTER安全密钥对result_json的签名(SHA256withRSA/PSS, saltlen=20) |
注1:本次请求使用的生物识别方式。生物识别方式及其定义见表1。例如:如果本次请求使用指纹识别,则填入0x1;目前只支持指纹识别。
注2:挑战因子为调用者为此次生物鉴权准备的用于签名的字符串关键是别信息,将作为result_json的一部分,供调用者识别本次请求。例如:如果场景为请求用户对某订单进行授权确认,则可以将订单号填入此参数。
注3:此数据为设备TEE中,将传入的challenge和TEE内其他安全信息组成的数据进行组装而来的JSON,对下述字段的解释如表2。例子如下:
{ "raw":"msg", "fid":"2", "counter":123, "tee_n":"TEE Name", "tee_v":"TEE Version", "fp_n":"Fingerprint Sensor Name", "fp_v":"Fingerprint Sensor Version", "cpu_id":"CPU Id", "uid":"21"}
表1:生物识别方式定义
生物识别方式 | 十六进制定义 |
---|---|
指纹识别 | 0x1 |
表2:result_json中个字段含义
字段名 | 含义 |
---|---|
raw | 调用者传入的challenge |
fid | (仅Android支持)本次生物识别认证的生物信息编号(如指纹识别则是指纹信息在本设备内部编号) |
counter | 防重放特征参数 |
tee_n | TEE名称(如高通或者trustonic等) |
tee_v | TEE版本号 |
fp_n | 指纹以及相关逻辑模块提供商(如FPC等) |
fp_v | 指纹以及相关模块版本号 |
cpu_id | 机器唯一识别ID |
uid | 概念同Android系统定义uid,即应用程序编号 |
表3:本接口err_code以及对应的解释
错误码 | 解释 |
---|---|
0 | 识别成功 |
90001 | 本设备不支持SOTER |
90002 | 用户未授权微信使用该生物认证接口 |
90003 | 请求使用的生物识别方式不支持 |
90004 | 未传入challenge或challenge长度过长(最长512字符) |
90005 | auth_content长度超过限制(最长42个字符) |
90007 | 内部错误 |
90008 | 用户取消授权 |
90009 | 识别失败 |
90010 | 重试次数过多被冻结 |
对于本接口,官方推荐的流程如下:
1.调用请求SOTER生物认证jsapi
2.jsapi返回成功之后,即err_code返回0,开发者本地进行校验签名,校验方法参见注4(可选)
3.异步调用指纹认证后台接口校验
注4:此处使用SHA256withRSA/PSS作为签名算法进行验签。此公式数学定义如下: bool 验签结果=verify(result_json,result_json_signature,auth_key)。
Https请求方式: POST
https://qyapi.weixin.qq.com/cgi-bin/soter/verify_signature?access_token=ACCESS_TOKEN
post数据格式json:
{ "openid":"OWefdsjafasEFD", "json_string" : "JSON", "json_signature" : "FDJSFSOIDUSAIDASJDASD" }
参数 | 必须 | 说明 |
---|---|---|
access_token | 是 | 企业号接口调用凭证 |
openid | 是 | 用户在企业号的openid |
json_string | 是 | requireSoterBiometricAuthentication接口返回的result_json_string字段(注意该字段需要json转义) |
json_signature | 是 | requireSoterBiometricAuthentication接口返回的result_json_signature字段 |
如果验证成功,返回
{"is_ok":ok}
验证失败返回
{"is_ok":false}
jsapi_ticket
生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是企业号号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket。
成功返回如下JSON:
{ "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
步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com
步骤2. 对string1进行sha1签名,得到signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事项
如出现invalid signature 等错误详见附录5常见错误及解决办法。
企业号部分JS-SDK(如:打开企业通讯录选人)的使用需要经过两部分的权限验证:
步骤1:通过API获取管理组JS-SDK凭据
与附录1-JS-SDK使用权限签名算法中的jsapi_ticket类似,开发者也是用access_token通过http GET请求获取管理组临时票据:https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token=ACCESS_TOKEN&type=contact
成功返回如下JSON:
{ "errcode": 0, "errmsg": "ok", "group_id": "g50a5axxxx91706a", "ticket": "WSfTOWPg35IBK9TpwfIi_dVRKrfigCi0TOCw-ZdFnLm4GgxxxxxxxxxxwB7AD64", "expires_in": 7200 }
步骤2:生成签名
签名算法与附录1-JS-SDK使用权限签名算法类似。参与签名的字段包括noncestr(随机字符串), 有效的group_ticket(在这里即是步骤1获取的ticket), timestamp(时间戳), url(要使用该JS-SDK的页面的url,生成的签名只允许在该url页面使用) 。对所有待签名参数按照字段名的ASCII码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
group_ticket=WSfTOWPg35xxxxxxxxxCi0TOCw-ZdFnLm4Ggvssk4suhakGwB7AD64&noncestr=Wm3WZYTPz0wzccnW×tamp=1447334894&url=http://your.website.com
将string1作sha1加密,得到签名signature:
f211c9c1b375aae79ad74685450149825b2b2353
版本1.1.0接口
基本类
传播类
保护类
JSSDK使用者请读这里,JSAPI用户可以跳过
卡券签名和JSSDK的签名完全独立,两者的算法和意义完全不同,请不要混淆。JSSDK的签名是使用所有JS接口都需要走的一层鉴权,用以标识调用者的身份,和卡券本身并无关系。其次,卡券的签名考虑到协议的扩展性和简单的防数据擅改,设计了一套独立的签名协议。另外由于历史原因,卡券的JS接口先于JSSDK出现,当时的JSAPI并没有鉴权体系,所以在卡券的签名里也加上了appsecret/api_ticket这些身份信息,希望开发者理解。
卡券 api_ticket
卡券 api_ticket 是用于调用卡券相关接口的临时票据,有效期为 7200 秒,通过 access_token 来获取。这里要注意与 jsapi_ticket 区分开来。由于获取卡券 api_ticket 的 api 调用次数非常有限,频繁刷新卡券 api_ticket 会导致 api 调用受限,影响自身业务,开发者必须在自己的服务全局缓存卡券 api_ticket 。参考获取api_ticket文档
卡券扩展字段cardExt说明
cardExt本身是一个JSON字符串,是商户为该张卡券分配的唯一性信息,包含以下字段:
字段 | 是否必须 | 是否参与签名 | 说明 |
---|---|---|---|
code | 否 | 是 | 指定的卡券code码,只能被领一次。use_custom_code字段为true的卡券必须填写,非自定义code和get_custom_code_mode(预存code模式的卡券)不必填写。 |
openid | 否 | 是 | 指定领取者的openid,只有该用户能领取。bind_openid字段为true的卡券必须填写,bind_openid字段为false不必填写。 |
timestamp | 是 | 是 | 时间戳,商户生成从1970年1月1日00:00:00至今的秒数,即当前的时间,且最终需要转换为字符串形式;由商户生成后传入,不同添加请求的时间戳须动态生成,若重复将会导致领取失败!。 |
nonce_str | 否 | 是 | 随机字符串,由开发者设置传入,加强安全性(若不填写可能被重放请求)。随机字符串,不长于32位。推荐使用大小写字母和数字,不同添加请求的nonce须动态生成,若重复将会导致领取失败。 |
outer_str | 否 | 否 | 领取渠道参数,用于标识本次领取的渠道值。 |
signature | 是 | 是 | 签名,商户将接口列表中的参数按照指定方式进行签名,签名方式使用SHA1,具体签名方案参见下文;由商户按照规范签名后传入。 |
签名说明
强烈建议开发者使用卡券资料包中的签名工具SDK进行签名或使用debug工具进行校验:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=cardsign
卡券签名cardSign说明
调用config接的时候传入参数debug: true 可以开启debug模式,页面会alert出错误信息。以下为常见错误及解决方法:
DEMO页面: