TECH NOTES / 开发实践

企业微信自建应用开发笔记

原笔记 2021-09-26 · 整理于 2026-10-05

企业微信自建应用的术语、授权流程、消息推送与旧版 JS-SDK 接入记录。

版本说明:这是一份包含 2018 年接口与界面的学习记录。保留术语与交互过程供理解,授权范围、返回字段、素材有效期和 JS-SDK 配置请以当前企业微信文档为准。

企业微信开发-自建应用配图 1

术语

  • corpid:企业ID 每个企业都有唯一的corpid:我的企业--企业信息

  • userid:每个成员都有唯一的userid(账号):通讯录--成员详情页

  • 部门id:每个部门都有唯一的id:通讯录-组织架构-部门右边的小圆点
    -tagid:每个标签都有唯一的标签id:通讯录-标签

  • agentid:每个应用唯一的id:应用与小程序-应用详情页

  • secret:企业应用中用于保障数据安全的钥匙【跟agentid配套】 ,目前的secret:

  • 自建应用secret:应用与小程序--应用--自建--某应用

  • 基础应用secret:【如审批,打卡等应用】企业与小程序--应用--基础--某应用--点开API小按钮

  • 通讯录管理secret:通讯录同步【需开启api接口同步】

  • 外部联系人管理secret:外部联系人--点开API小按钮

  • access_token:是企业后台去企业微信的后台获取信息时的重要 票据,由corpid和secret产生。所有接口在通信时都需要携带access_token用于验证接口的访问权限

每个企业号CorpID只有一个,但Secret却有几种,不同Secret获取到的令牌它的作用范围是不同的。

Secret分类如下:

  • 应用Secret:点击“应用详情”就看到了
  • 通讯录管理Secret:查看方式是“管理工具/通讯录同步”
  • 管理组Secret:查看方式是“我的企业/权限管理/管理组”(你如果找不到也很正常,因为这是老用户才有的“待遇”,现已退出历史舞台,奸笑ing)。

应用

按提供方来分有三种:

  1. 基础应用:由微信提供;
  2. 第三方应用:开放体系下的第三方服务商提供;
  3. 自建应用:我们自己新建的,一般我们也都是需要自建应用进行开发。

按作用来分有两种:

  1. **主页型应用:**用户点击应用后直接打开一个链接;
  2. **消息型应用:**可以像公众号一样设置多个菜单,每个菜单可以配置不同的响应方式。

以下展示一个应用详情界面:

企业微信开发-自建应用配图 2

应用详情

从上图我们可以看出,一个应用主要包含以下几方面的信息:

  1. AgentId:应用ID,新建应用后由微信生成;
  2. Secret:应用的Secret,结合CorpID用来获取access_token;
  3. 可见范围:哪些人能看到这个应用(可按人、按部门或者按标签进行设定);
  4. **管理员:**可对该应用进行管理的人;
  5. 可信域名:应用网页相关地址需要满足对应接口的可信域名配置要求。原笔记中的示例为 www.example.com 或 test.example.com:3000,实际要求请按当前控制台与接口文档核对;
  6. 工作台应用主页:配置用户点击应用后跳转的链接地址,配置后该应用即为主页型应用;
  7. **自定义菜单:**设置后表示应用为消息型工作台应用主页链接将失效,设置方式类似于公众号。

访问令牌

访问令牌(access_token)是我们开发的第一步,我们在调用微信接口前,往往需要先获取令牌,然后才能“为所欲为” :- )。

令牌只能通过企业ID(CorpID)+Secret来获取,CorpID的查看方式如下:

企业微信开发-自建应用配图 3

每个企业号CorpID只有一个,但Secret却有几种,不同Secret获取到的令牌它的作用范围是不同的。

Secret分类如下:

  • 应用Secret:点击“应用详情”就看到了
  • 通讯录管理Secret:查看方式是“管理工具/通讯录同步”
  • 管理组Secret:查看方式是“我的企业/权限管理/管理组”(你如果找不到也很正常,因为这是老用户才有的“待遇”,现已退出历史舞台,奸笑ing)。

企业微信开发-自建应用配图 4

应用Secret

企业微信开发-自建应用配图 5

通讯录管理Secret

企业微信开发-自建应用配图 6

曾经的管理组Secret

获取令牌的接口是:

GET https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=CORPID&corpsecret=SECRECT

返回格式如下:

json
{
  "errcode": 0,
  "errmsg": "",
  "access_token": "accesstoken000001",
  "expires_in": 7200
}

需要注意的是access_token具有时效性,超过7200(expires_in的值)秒后就会过期,又因为获取令牌的接口有访问频率的限制,所以你需要定时刷新access_token。

详细文档请参考:获取access_token - 企业微信。

场景一:网页授权登录

参考文档:网页授权登录 - 企业微信

这是我们使用频率最高的一个场景,简单的说就是:如何在用户进入应用的时候获取到他的userid(或者更详细的信息)?

授权登录使用OAuth2.0协议,先来看看微信官方提供的接入流程图:

企业微信开发-自建应用配图 7

总结下来就是三步:

  1. 用户访问时先跳微信服务器,同时你需要告诉微信服务器一个跳转地址
  2. 微信服务器先做验证,验证通过后回跳到你提供的地址,并同时带上一个跟用户信息相关的code
  3. 你根据这个code再调用另一个接口就能获取到用户数据了,一般在后端服务器做处理

第1,2步都是为了拿到code,第3步才是获取用户信息。

假如我有一个主页型应用,基本信息如下:

那么生成的网页链接是这样的(该链接可设置为主页地址、菜单链接和推送消息的跳转链接):

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx10101&redirect\_uri=https%3A%2F%2Ftest.example.com%3A3000%2Fapi%2Fmyredirect&response\_type=code&scope=snsapi\_base#wechat\_redirect

这里有两点需要注意的地方:

  1. redirect_uri的值必须经过urlencode处理(可直接调用JS的全局函数encodeURIComponent)
  2. redirect_uri的host部分(即域名+端口)必须和可信域名配置一致
  3. 如果你将一些信息从用户点击传递到回调地址,那么可以设置state参数(只有这一种传递方式)

获取用户信息的接口是(注意code只能使用一次):

GET https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access\_token=ACCESS\_TOKEN&code=CODE

返回结果:
a) 当用户为企业成员时(无论是否在应用可见范围之内)返回示例如下:

json
{
   "errcode": 0,
   "errmsg": "ok",
   "UserId":"USERID",
   "DeviceId":"DEVICEID"
}

参数

说明

errcode

返回码

errmsg

对返回码的文本描述内容

UserId

成员UserID。若需要获得用户详情信息,可调用通讯录接口:读取成员。如果是互联企业或者企业互联,则返回的UserId格式如:CorpId/userid

DeviceId

手机设备号(由企业微信在安装时随机生成,删除重装会改变,升级不受影响)

b) 非企业成员时,返回示例如下:

json
{
   "errcode": 0,
   "errmsg": "ok",
   "OpenId":"OPENID",
   "DeviceId":"DEVICEID",
   "external_userid":"EXTERNAL_USERID"
}

参数

说明

errcode

返回码

errmsg

对返回码的文本描述内容

OpenId

非企业成员的标识,对当前企业唯一。不超过64字节

DeviceId

手机设备号(由企业微信在安装时随机生成,删除重装会改变,升级不受影响)

external_userid

外部联系人id,当且仅当用户是企业的客户,且跟进人在应用的可见范围内时返回。如果是第三方应用调用,针对同一个客户,同一个服务商不同应用获取到的id相同

出错返回示例:

json
{
   "errcode": 40029,
   "errmsg": "invalid code"
}

场景二:扫码授权登录

参考文档:扫码授权登录 - 企业微信

我们这里只讨论Web网页扫码登录的场景,移动端扫码登录请参考官方文档。

在开发扫码登录前,你需要先开启应用的网页接入功能,开启方式是点击“应用详情/企业微信授权登录/Web网页”,直接将可信域名的值复制过来设置即可。

扫码登录与场景一类似,同样是OAuth2.0协议,也是先拿code再拿用户信息,交互流程图如下:

企业微信开发-自建应用配图 8

假如我有以下基本信息:

那么生成的扫码链接是这样的:

https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=wx10101&agentid=1000000&redirect\_uri=https%3A%2F%2Ftest.example.com%3A3000%2Fapi%2Fmyredirect

用户打开该链接后,就会出现一个二维码,用户使用企业微信扫码后,就会跳转到回调地址并带上授权code,通过code获取用户信息的接口为:

GET https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access\_token=ACCESS\_TOKEN&code=CODE

场景三:素材管理

参考文档:素材管理 - 企业微信

素材管理比较简单,直接调用微信接口即可,不过需要注意的是,目前企业微信只开放了临时素材的管理接口(今天是2018-05-04),所有通过接口上传的media_id仅三天内有效。

后台管理页面中的资源标识不代表公开 API 承诺长期可用。应用应按正式素材接口处理上传、有效期与重新获取,避免依赖后台页面的内部请求。

场景四:消息推送

参考文档:发送应用消息 - 企业微信

本质上就是调用一个接口而已。

需要注意的是,消息都是以应用为单位显示的(在发送消息的时候会指定agentid),所以你调用接口所使用的access_token必须是通过该应用的Secret获得的。

如果你希望对消息内容进行排版(用html的方式),且用户点击后,你希望跳转到一个网页地址去,我推荐你使用“文本卡片消息”。

企业微信开发-自建应用配图 10

我们之前还遇到过一个场景是,希望用户在点击消息后,跳转到其他应用去,但遗憾的是目前微信还不支持跨应用跳转。

场景五:JS-SDK

参考文档:JS-SDK - 企业微信

要用JS-SDK,客户端必须要进行SDK初始化;

要进行初始化,必须要有个签名;

要有个签名,必须要有个jsapi_ticket。

所以我们先说说jsapi_ticket。jsapi_ticket其实跟access_token类似,它也会过期,也有频率限制,所以我们也需要对jsapi_ticket进行定时刷新,获取jsapi_ticket的接口如下:

GET https://qyapi.weixin.qq.com/cgi-bin/get\_jsapi\_ticket?access\_token=ACCESS\_TOKEN

接下来是签名,分享一个node的签名算法供参考:

javascriptconst
const qs = require('querystring');

/**
 * 签名生成算法
 * @param {*} query
 */
function sign(query) {
  // 1.排序
  const obj = qs.parse(query);
  const message = Object.keys(obj).sort().map(key => `${key}=${obj[key]}`).join('&');
  // 2.加密
  const signature = crypto.createHash('sha1').update(message, 'utf8').digest('hex');
  return signature;
}

// 测试
const query = 'noncestr=Wm3WZYTPz0wzccnW&jsapi_ticket=EXAMPLE_TICKET&timestamp=1414587457&url=http://mp.weixin.qq.com?params=value';
console.log(sign(query));
// 示例票据仅用于演示,结果以实际参数为准。

如果你不确定你的算法是否正确,可以去微信提供的在线签名工具进行验证。

有了签名以后,我们就可以进行SDK初始化了,初始化前需要引入js文件:

http://res.wx.qq.com/open/js/jweixin-1.2.0.js(支持https)

然后开始执行初始化:

javascriptwx.config({
  beta: true,    // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
  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可以在这里更新签名。
});

这里需要注意的是所有参数都是大小写敏感的,比如后端签名时参数是noncestr,但是前端初始化时是nonceStr。

初始化成功后,就可以尽情地浪了。使用企业微信打开以下链接即可体验官方提供的Demo页面:

http://work.weixin.qq.com/api/jsapidemo (二维码自动识别)

最后说两句

  1. 严格按照文档中要求的去做会少栽很多坑,不要看漏任何一个细节,例如大小写;
  2. 如果你已经按照文档要求去做了,还是未达到理想效果,那你可以安装一个开发者工具,尝试下从控制台输出信息去进行调试(微信的开发者工具是可以模拟整个微信环境的);
  3. 如果还是解决不了你的问题,那你就直接找客服吧(企业微信的客服反馈还是很及时的,在企业微信客户端的客服对话框中,输入“人工”即可)。

企业微信客服入口

文章配图