前端搭建企业微信应用开发环境

背景

企业微信应用开发分为两种开发方式:

  1. 服务商代开发应用
  2. 企业自建应用

使用服务商代开发模式,由于代开发应用,企业微信需要认证,无法调用企业微信sdk; 而企业自建应用,无需进行认证,可以调用企微提供的开放能力。

本文主要内容是前端如何搭建一个企业微信自建应用的开发环境:

  1. 创建一个自建应用
  2. 介绍企业微信的授权流程
  3. 前端调用流程和后端调用企微的流程
  4. 搭建过程中的一些报错

1. 创建企微自建应用

1.1 新建应用

在企业微信后台下->应用管理->应用->创建应用

此处需要记住 AgentId,其中Secret前端不需要。

这样一个自建应用就创建完成了。

下面介绍下配置到聊天附件栏、和聊天工具栏的配置和表现形式。

1.2 聊天工具栏

从上面页面下可以点击配置到聊天工具栏,进行配置链接,此处的链接可以参考我上一篇文章企业微信侧边栏本地开发调试

企业微信中表现形式:

1.3 聊天附件栏

从上面页面下可以点击配置到聊天附件栏,进行配置链接,同上。

企业微信中表现形式:

2. 企微授权流程梳理

我们先看一下企业微信整体的鉴权流程,如下图:

前后端调用具体的流程图如下:

接下来我们需要搭建创建一个前端项目和一个node服务(这里使用nestjs)。

3. 前、后端调用流程

这里我们主要分为两个部分,一部分是前端代码,一部分是后端代码。

3.1 前端代码部分

具体步骤参考企业微信JS-SDK开发文档,我这里只做重要的讲解。

3.1.1 引入企微相关sdk

js 复制代码
<!--  需要调用JS接口的页面引入如下JS文件 z  -->
<script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js" type="text/javascript"></script>
<!--调用 wx.agentConfig需要引入 jwxwork sdk-->
<script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>

3.1.2 通过config接口注入权限验证配置

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用)。

js 复制代码
wx.config({
    beta: true,// 必须这么写,否则wx.invoke调用形式的jsapi会有问题
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,企业微信的corpID
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。

注意:此处timestamp、nonceStr、signature由后端提供,其余参数均可知

3.1.3 agentConfig注入应用的权限

在ready后调用agentConfig注入实际开发中需要的权限,例如转发、分享等。

js 复制代码
wx.ready(function(){
    wx.agentConfig({
        corpid: '', // 必填,企业微信的corpid,必须与当前登录的企业一致
        agentid: '', // 必填,企业微信的应用id
        timestamp: , // 必填,生成签名的时间戳
        nonceStr: '', // 必填,生成签名的随机串
        signature: '',// 必填,签名,见附录1
        jsApiList: [], //必填
            success: function(res) {
            // 回调
        },
        fail: function(res) {
            if(res.errMsg.indexOf('function not exist') > -1){
                alert('版本过低请升级')
            }
        }
    });
});

注意:此处timestamp、nonceStr、signature由后端提供,还有一点需要注意的是wx.config和wx.agentConfig需要后端的提供的数据只是参数名相同,内容是不同的。

3.1.4 判断是否授权

首先在进入页面时会先判断当前url 是否有code 参数,如果有code则走登录逻辑(企业微信侧边栏一般默认都是静默登录),否则就跳转企业微信授权页面。

如果没有前端代码如下:

js 复制代码
https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE&agentid=AGENTID#wechat_redirect

无授权文档说明,进行跳转授权,参数说明如下:

如果有code则需要后端获取访问用户身份

下面我们需要搭建一个后端服务,去调用企业微信的接口。

3.2 搭建后端服务

主要功能是用于自身开发服务器向企微服务请求ticket,并将签名信息返回给前端。

最主要的流程是:

3.2.1 通过corpid, corpsecret获取access_token

js 复制代码
  /** 获取企业微信jsapi的ticket */
  async getAccessToken(query) {
    try {
      const { corpid, corpsecret } = query
      const res = await firstValueFrom(
        this.httpService.get(`https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${corpsecret}`)
      )
      if (res.data.errcode !== 0) {
        throw new HttpException("获取失败", HttpStatus.OK);
      }
      return res.data.access_token
    } catch (error) {
      handleError(this.logger, error, {
        common: "获取企业微信Access Token失败",
      });
    }
  }

3.2.2 调用企微接口get_jsapi_ticket获取ticket, 用于wx.config签名返回

获取到ticket进行签名,返回给前端wx.config的三个参数

js 复制代码
  /** 获取企业微信config的ticket 用于config */
  async getConfigTicket(accessToken: string) {
    try {
      const res = await firstValueFrom(
        this.httpService.get(`https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=${accessToken}`)
      )
      return res.data.ticket
    } catch (error) {
      handleError(this.logger, error, {
        common: "获取企业微信config的ticket失败",
      });
    }
  }

签名:

js 复制代码
  /**
   * 生成随机字符串
   * @param length 字符串长度,默认16
   * @returns 随机字符串
   */
  private generateNonceStr(length = 16): string {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let result = '';
    for (let i = 0; i < length; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return result;
  }
}


  /**
   * 生成微信JS-SDK签名
   * @param jsapi_ticket 微信JSAPI Ticket
   * @param url 当前网页URL(不包含#及其后面部分)
   * @returns 返回签名所需的所有参数
   */
  async generateQWSignature(query) {

    const { url, type, corpid, corpsecret } = query
    const token = await this.getAccessToken({ corpid, corpsecret })
    // 0. 获取jsapi_ticket
    const ticket = type === 'config' ? await this.getConfigTicket(token) : await this.getAgentConfigTicket(token)

    // 1. 生成随机字符串(16位)
    const noncestr = this.generateNonceStr();

    // 2. 生成时间戳(秒级)
    const timestamp = Math.floor(Date.now() / 1000);

    // 3. 按固定顺序拼接字符串
    const string1 = `jsapi_ticket=${ticket}&noncestr=${noncestr}&timestamp=${timestamp}&url=${url}`;

    // 4. 生成SHA1签名
    const signature = createHash('sha1')
      .update(string1)
      .digest('hex');

    return {
      noncestr,
      timestamp,
      url,
      signature,
    };
  }

3.2.3 调用企微接口get获取ticket, 用于wx.agentConfig签名返回

js 复制代码
  /** 获取企业微信agent_config的 jsapi的ticket 用于接口权限 */
  async getAgentConfigTicket(accessToken: string) {
    try {
      const res = await firstValueFrom(
        this.httpService.get(`https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token=${accessToken}&type=agent_config`)
      )
      return res.data.ticket
    } catch (error) {
      handleError(this.logger, error, {
        common: "获取企业微信agent_config的ticket失败",
      });
    }
  }

签名函数同上,区分类型即可。

4. 搭建过程中的问题

  1. 获取wx.config和wx.agentConfig的ticket弄混,调用的接口是不一样的
  2. 接口访问需要添加ip白名单
  3. 报错40093,签名的url需要添加/
  4. 要用应用的Secret获取access_token来获取jsapi_ticket和agent jsapi_ticket,不要用企业的corpSecret

5. 总结

最后总结一下,搭建一个企业微信的应用开发环境,需要理解企业微信授权的整体流程,过程中也遇到了一些问题,总结下希望能对大家有一点点的帮助。如有错误,请指正O^O!

相关推荐
晴殇i几秒前
前端视角下的单点登录(SSO)从原理到实战
前端·面试·trae
圆心角3 分钟前
深入解析协商缓存(弱缓存)
前端·浏览器
鹏北海13 分钟前
vue-route-query-hook:一个用于 Vue 3 的 Composable,提供响应式参数与 URL 查询参数之间的双向同步功能
前端·javascript·vue.js
VisuperviReborn24 分钟前
打造自己的前端监控---前端接口监控
前端·javascript·架构
程序员海军24 分钟前
这才是Coding该有的样子!重新定义编程显示器
前端·后端
阳树阳树25 分钟前
小程序鉴权机制分析
前端
BUG收容所所长25 分钟前
如何用React打造一个完整的移动端问卷调查应用?
前端·react.js·开源
Cache技术分享26 分钟前
151. Java Lambda 表达式 - 使用 Consumer 接口处理对象
前端·后端
YGY_Webgis糕手之路28 分钟前
OpenLayers 综合案例-加载gif图
前端·gis
小高00730 分钟前
🚀前端性能优化实录:把 5 秒白屏降到 1.2 秒,只做 7 件事
前端·javascript·面试