你笑了

你的笑,是星星跳跃浪花的笑

0%

企微自建应用-考勤

企业内部应用

企业微信提供了通讯录管理、客户联系、身份验证、应用管理、消息推送、素材管理、OA、效率工具、企业支付、企业互联、会话内容存档、电子发票、家校沟通、家校应用、政民沟通等API,企业可以使用这些API,为企业接入更多个性化的办公应用

身份验证

网页授权登录

OAuth的授权登录方式

从企业微信终端打开的网页可获取成员的身份信息,从而免去登录的环节

企业应用中的URL链接(包括自定义菜单或者消息中的链接),均可通过OAuth2.0验证接口来获取成员的UserId身份信息

OAuth2

允许用户在不告知第三方自己的账号密码情况下,通过授权方式,让第三方服务可以获取自己的资源信息。RFC 6749

Authorization Code模式

流程如下

包含四个角色

  • ResourceOwner为资源所有者,即为用户
  • User-Agent为浏览器
  • AuthorizationServer为认证服务器,可以理解为用户资源托管方,比如企业微信服务端
  • Client为第三方服务,比如企业自建应用

调用流程为:

  • A) 用户访问第三方服务,第三方服务通过构造OAuth2链接(参数包括当前第三方服务的身份ID,以及重定向URI),将用户引导到认证服务器的授权页

    用户访问企业的自建应用时,设置的入口链接如果是 授权链接,则可以引导到企微认证服务器授权页

  • B) 用户选择是否同意授权

    若选择默认方式,可以不弹出授权页面,直接重定向到 redirection_uri

  • C) 若用户同意授权,则认证服务器将用户重定向到第一步指定的重定向URI,同时附上一个授权码

    如果可信域名和授权链接 redirection_uri 写的本机,会访问到本地,可以看到 code

  • D) 第三方服务收到授权码,带上授权码来源的重定向URI,向认证服务器申请凭证

    获取的 access_token 可以关联到重定向URI

  • E) 认证服务器检查授权码和重定向URI的有效性,通过后颁发AccessToken(调用凭证)

D)与E)的调用为后台调用,不通过浏览器进行

企微OAuth2流程图

网页授权的可信域名
  • REDIRECT_URL中的域名,需要先配置为应用的“可信域名”,否则跳转时会提示“redirect_uri参数错误”

  • 配置的可信域名,必须与访问链接的域名完全一致;若访问链接URL带了端口号,端口号也需要登记到可信域名中

    假定重定向访问的链接是:http://mail.qq.com:8080/cgi-bin/helloworld

    则可信域名需要配置为 mail.qq.com:8080

静默授权与手动授权
  • 静默授权:用户点击链接后,页面直接302跳转至 redirect_uri?code=CODE&state=STATE

  • 手动授权:用户点击链接后,会弹出一个中间页,让用户选择是否授权,用户确认授权后再302跳转至 redirect_uri?code=CODE&state=STATE

个人敏感信息授权管理
  • 用户首次进入oauth2页面进行手动授权后,30天内再次进入应用页面不会再弹出授权页,默认授权用户当前授权的敏感信息。若30天内用户需要修改个人敏感信息授权,可进入应用详情页的“个人敏感信息授权管理”页面,重新更改个人敏感信息授权
缓存方案建议

通过OAuth2.0验证接口获取成员身份会有一定的时间开销。对于频繁获取成员身份的场景,建议采用如下方案:

  1. 企业应用中的URL链接直接填写企业自己的页面地址

    即授权链接的url http://open.weixin.qq.com/connect/oauth2/authorize? 填写自己的页面地址,自己判断是否去企微重新获取

  2. 成员操作跳转到步骤1的企业页面时,企业后台校验是否有标识成员身份的cookie信息,此cookie由企业生成

  3. 如果没有匹配的cookie,则重定向到OAuth验证链接,获取成员的身份信息后,由企业后台植入标识成员身份的cookie信息

  4. 根据cookie获取成员身份后,再进入相应的页面

服务端API业务流程

获取 access_token

调用企微API接口的第一步,需要通过 access_token 来鉴权调用者身份

  • 不同的业务API可能需要不同来源的 access_token,需要明确 access_token 的来源

  • 每个应用有独立的secret,获取到的access_token只能本应用使用,进行缓存时需要区分应用来进行存储

    access_token至少保留512字节的存储空间。

  • 不能频繁调用gettoken接口,否则会受到频率拦截。当access_token失效或过期时,需要重新获取。

  • access_token的有效期通过返回的expires_in来传达,正常情况下为7200秒(2小时),有效期内重复获取返回相同结果,过期后获取会返回新的access_token。

    企业微信可能会出于运营需要,提前使access_token失效,开发者应实现access_token失效时重新获取的逻辑

  • 不能将 access_token 返回给前端,需要保存在后台,所有访问企业微信api的请求由后台发起

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
async getOrRefreshToken(params: {
refresh: boolean,
}) {
const { refresh } = params;
if (refresh) { // 判断请求返回的code,如果是token失效,则强制刷新
await this.getToken()
} else if (!this._accessToken) {
await this.getToken()
}
return this._accessToken;
}

private async getToken() {
const ret = await httpClient.get('https://qyapi.weixin.qq.com/cgi-bin/gettoken', {
params: {
corpid: this.corpId,
corpsecret: this.corpSecret
}
})

if (ret['errcode'] === 0) {
this._accessToken = ret['access_token']
console.log('accessToken = ', this._accessToken)
// this._expiresIn = this.getSecond() + ret['expires_in'] - this.refreshTokenTimeInMins * 60 // second
} else {
throw Error(`access token 获取失败,${ret['errmsg']}`)
}
}

同步组织架构

  • 后端程序启动时需要先通过 access_token 获取一遍组织架构信息

  • 企业自建应用 不受 通讯录管理的 安全机制限制

  • 只有通讯录同步助手(一种应用类型)才受安全机制限制

    成员ID列表 api forbidden 48002 问题

获取子部门ID列表

不填部门id,获取全量组织架构

获取部门成员详情
  • 根据获取的部门ID获取该部门的成员信息
  • 只能获取应用配置的可见范围内的成员信息
  • 不递归获取子部门的成员

判断是不是当前部门的leader

1
userInfo['is_leader_in_dept'][userInfo['department'].findIndex((e) => e === depId)] === 1 ? 'true' : 'false'
本地保存

将组织架构信息保存到本地

获取访问用户身份

参数

  • code

    通过成员授权获取到的code,最大为512字节。每次成员授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期

业务逻辑

  • 获取到用户 userid 后,通过同步到本地的组织架构信息,查询该 userid 的信息,例如自己配置的用户角色等

  • 返回 token,作为前端后续调用自己后端服务的凭证

    将获取到的 userid 信息,作为返回 token 的 payload,包括 userid,role等

成员管理

读取成员

没有入职及离职时间,可在创建成员时通过新增扩展字段-入职时间来设置

消息推送

发送应用消息

打卡、审批等操作,在自己的后端处理完业务逻辑之后,可以向企微用户发送通知消息

文本消息
文本卡片消息
按钮交互型
  • 需要提前配置回调地址

    如果报错 43012,则需要配置

    注意 nginx转发路由也要拼接

企业管理后台配置

通讯录secret

在 安全与管理-> 管理工具 -> 通讯录同步->

  1. 开启接口同步

  2. 查看 secret

  3. 配置可信IP

    后端的外网ip地址

应用管理

自建应用

创建应用后可以看到 AgentId、Secret

这个 secret 是应用的secret,获取 access_token

可见范围
  • 用来添加组织架构

通过 access_token 同步该组织架构中的成员

应用主页
  • 设置从工作台点击进入的网页

    如果要获取 code,则需要构建一个 网页授权链接

    1
    2
    3
    4
    5
    6
    http://open.weixin.qq.com/connect/oauth2/authorize?
    appid=ww970b9d959208f458&
    redirect_uri=https://www.dawei.cn:12345&
    response_type=code&
    scope=snsapi_base&
    state=%7B%22school_id%22%3A%22school_qiwei%22%7D#wechat_redirect

    其中 redirect_uri(IP+Port)需要配置为可信域名

接收消息
  • 如果要发送应用消息中的模板卡片消息,则需要配置一个回调地址

    • url 配置为后端入口

    • token、EncodingAESKey 自动生成,用于校验收到的信息

      node 用腾讯的 @wecom/crypto

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      import { getSignature, decrypt } from '@wecom/crypto'

      async handleGetCallback(query: GetCallbackDto) {
      const { msg_signature, timestamp, nonce, echostr } = query;
      const sign = getSignature(Conf.qiwei.callbackToken, timestamp, nonce, echostr)
      if (sign !== msg_signature) {
      throw Error('illegal msg')
      }
      const { message } = decrypt(Conf.qiwei.callbackEncoding, echostr)
      return message.trim()
      }
      // 注意如果框架有统一的返回格式,返回结果需要特殊处理,只能返回解密后的message字符串

      如果出现 openapi 回调地址不通过,可通过工具 建立连接->测试回调模式 来查看返回的结果是不是正确的

企业可信IP
  • 需要把后端服务的外网IP加入

    如果不知道外网ip,直接调用接口,报错信息会给出当前网络的外网ip

网页授权及JS-SDK
可信域名

需要配置为OAuth2.0网页授权功能的回调域名

不能包含协议头,不支持IP地址及短链域名

  • 配置完需要验证,下载一个文件,放到根目录

    如果后端有http服务,例如 nest,可以将文件放在服务器的静态目录public下,这样企微可以通过配置的可信域名访问到本地的文件,就可以验证通过

    1
    2
    3
    4
    5
    6
    7
    //  配置静态资源
    app.useStaticAssets(join(__dirname, '../public'), {
    prefix: '/',
    setHeaders: res => {
    res.set('Cache-Control', 'max-age=2592000')
    }
    });

后端自己测试

  1. 将可信域名配置为后端的地址 www.dawei.cn:12345,将验证文件放在项目的静态目录下,完成验证。

    这里需要 https监听的端口

  2. 授权链接中的 redict_url 设为后端地址 www.dawei.cn:12345

    http://open.weixin.qq.com/connect/oauth2/authorize?appid=ww970b9d95920458&redirect_uri=https://www.dawei.cn:12345&response_type=code&scope=snsapi_base&state=%7B%22school_id%22%3A%22school_qiwei%22%7D#wechat_redirect

  3. 在企微客户端的用户窗口,发送网页授权链接,点击链接,企微就会访问到后端,拿到带有 code 的信息,再用code去 获取访问用户身份

    1
    ::ffff:172.18.228.110 "GET /?code=_k2rDYZzyNMvcdxxOsEEBOoDFmMjpPIljQEVD13Q&state=%7B%22school_id%22%3A%22school_qiwei%22%7D" undefined Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko)  Mobile/15E148 wxwork/4.1.20 MicroMessenger/7.0.1 Language/zh ColorScheme/Light undefined

    生产环境,前端在进入应用的时候会携带code

    https://dawei.net:12345/?code=QjK-z8Cczypi1m8cWtB_JjO06-yjfv2HitxubUw&state=%7B%22school_id%22%3A%22school_qiwei%22%7D