企业微信 之 网页鉴权

一、流程 

1. 前端 => 获取code

前端鉴权,拿到code后,传递给后端

2. 后端 => 获取access_token

获取access_token

其它的业务API接口,都需要依赖于access_token来鉴权调用者身份

3. 后端 => 获取企业的jsapi_ticket

获取企业的jsapi_ticket

进行签名算法,生成signature        wx.config和wx.agentConfig 签名不可共用

4. 前端 => 获得权限配置

前端请求接口,拿到数据后进行wx.config以及wx.agentConfig配置

5. 前端 => 获取外部联系人userId

获取当前外部联系人userid

6. 后端 =>  获取用户的unionid

获取客户详情

7. 后端 => 获取用户基本信息

获取访问用户身份

前端把code传递给后端后,后端通过code和access_token获取数据

ps : 一般这里后端可以返回token给前端,前端后续的请求是携带即可

unionid:   外部联系人在微信开放平台的唯一身份标识(微信unionid),通过此字段企业可将外部联系人与公众号/小程序用户关联起来。仅当联系人类型是微信用户,且企业或第三方服务商绑定了微信开发者ID有此字段。

通过获取的 unionid 与 公司后台已存在的 unionid 匹配,从而获取该外部联系人在 公司后台 的基本信息,返回到前端进行展示

二、实际操作

1. 引入js文件

// 在index.html中,加入
<script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>

2. App.vue

企业微信侧边栏一般潜入h5页面,这里做个页面配置,限制宽度等

<template>
  <div id="app" :class="{'fixed-app': fixedStatus}">
    <router-view/>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 是否固定app宽度
      fixedStatus: false
    };
  },
  created() {
    this.resize();
    window.addEventListener('resize', this.resize, false);
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.resize, false);
  },
  methods: {
    resize() {
      if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) { // 移动端
        // 移动端操作
        this.fixedStatus = false;
      } else {
        // pc端操作
        // 固定app宽度
        this.fixedStatus = true;
      }
    }
  }
};
</script>

<style lang="scss">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  font-size: .14rem;
  &.fixed-app {
    max-width: 750px;
    min-width: 320px;
    margin: 0 auto;
    box-sizing: border-box;
    font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue","Microsoft Yahei",sans-serif;
    overflow: hidden;
  }
}
</style>

3. 配置可信域名

现在企业微信更新后,只能访问外网地址,本地调试时先跳过code授权之类的

等测试时,再进行授权调试

配置可信域名:应用管理 -> 点击创建的应用 -> 网页授权及 JS-SDK

4. 获取code

构造网页授权链接,获取code : 构造网页授权链接 

window.location.href = 链接即可。如果请求成功,code会显示在浏览器地址上  

getWeixinGetAuthorityUrl() {
  // 配置参数 => 可以直接写死,也可以通过接口获取
  const opt = {
    appid: 'xxx', // 企业微信的appid
    redirect_uri: encodeURIComponent(window.location.href), // 重定向地址,需外网地址,需要进行UrlEncode
    response_type: 'code', // 返回类型,固定为:code
    scope: 'snsapi_base' // 静默授权,可获取成员的基础信息(UserId与DeviceId)
  };
  const str = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${opt.appid}&redirect_uri=${opt.redirect_uri}&response_type=${opt.response_type}&scope=${opt.scope}&state=weixin#wechat_redirect`;

  // 重新跳转到当前位置
  /** 当然会出现请在企业微信客户端打开链接,只能配置外网环境,在里面进行测试了,但是成功后,地址栏后面就有code参数 */
  window.location.href = str;
}

5. 注入权限验证配置

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

方式一

直接写在页面中进行配置

window.wx.config({
    // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
    beta: true,

    // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印
    debug: true, 
    
    // 必填,企业微信的corpID,必须是本企业的corpID,不允许跨企业使用
    appId: 'xxx', 
    
    // 必填,生成签名的时间戳
    timestamp: '1204314209', 
    
    // 必填,生成签名的随机串
    nonceStr: 'L12kHl4M4l1BFNs2', 
    
    // 必填,签名,见 附录-JS-SDK使用权限签名算法
    signature: '334bgd6d78d50agds552fab434bb39b780fb008e',
    
    // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
    jsApiList: ["getCurExternalContact", "openUserProfile", "hideOptionMenu", "agentConfig"] 
});

方式二

通过接口让后端返回

ps : 这里可以利用特性 

script标签的onload事件都是在外部js文件被加载完成并执行完成后才被触发

  // 1. 获得head元素
  const headDom = document.querySelector('head');

  // 2. 创建script元素
  const scriptDom = document.createElement('script');

  // 3. 设置script元素的属性
  scriptDom.type = 'text/javascript';

  /**
   * 4. 监听script元素的加载事件,加载完成后执行回调
   *    这里已经执行完成了scriptDom,也就是权限已经注入了,但是还没有执行wx.ready
   */
  scriptDom.onload = scriptDom.onreadystatechange = function() {};

  /**
   * 5. 设置script元素的src属性
   *    01. 获取当前页面的url => (不包含#及其后面部分)
   *    例如:http://localhost:8080/ins-web/#/home => http://localhost:8080/ins-web
   *    02. 将url传给后端,后端根据url生成签名 => (后端需要提供一个接口,接收url参数,返回签名)
   *    03. 将签名返回给前端 => (后端接口返回的数据结构为:{appId: '', timestamp: '', nonceStr: '', signature: ''})
   */
  const locationUrl = encodeURIComponent(window.location.href.split('#')[0]);
  const url = `/ins-api/wechat/jsapi/signature?url=${locationUrl}`;
  scriptDom.src = url;
  // https://xxx.com//ins-api/wechat/jsapi/signature?url=https%3A%2F%2Fxxx.com%2F%3Fcode%3DlVmYFNlGQTrRQsBg1Cm1ngSDSIlSr5BQzgai4ZDbW5k%26state%3Dweixin

  // 6. 将script元素添加到head元素中,此时浏览器会自动加载script元素,执行其中的代码,从而注入权限
  headDom.appendChild(scriptDom);

6.  注入应用的权限

 通过agentConfig注入应用的权限

wx.agentConfig({
    // 必填,企业微信的corpid,必须与当前登录的企业一致
    corpid: 'xxx', 

    // 必填,企业微信的应用id (e.g. 1000247)
    agentid: 'xxx', 

    // 必填,生成签名的时间戳
    timestamp: '1421314709', 

    // 必填,生成签名的随机串
    nonceStr: 'xxx', 

    // 必填,签名,见附录-JS-SDK使用权限签名算法
    signature: 'xxx',

    //必填,传入需要使用的接口名称
    jsApiList: ["getCurExternalContact", "openUserProfile", "hideOptionMenu", "openEnterpriseChat"], 
    
    // 成功的回调
	success: function(res) {
        
    },

    // 失败的回调
    fail: function(res) {
        if(res.errMsg.indexOf('function not exist') > -1){
            alert('版本过低请升级')
        }
    }
});

方式一

如果权限是通过方式一获取的

//注入权限验证配置
window.wx.config({
  beta: true,
  debug: true, 
  appId: '', 
  timestamp: '', 
  nonceStr: '',
  signature: '',
  jsApiList: [] 
});

// 注入权限验证配置
setTimeout(()=>{
  window.wx.ready(() => {
    // 请求获取应用权限
    axios.get('balabalabala').then(cof => {
        const confObj = cof.data.data || {};
        // 注入应用的权限
        window.wx.agentConfig({
          // 通过后端接口直接获取也可
          ...confObj,
      
          success: function(res) {},
          fail: function(res) {}
        });
      })
  });
},1000)

方式二

如果权限是通过方式二获取的,可以在onload中继续操作

const headDom = document.querySelector('head');
const scriptDom = document.createElement('script');
scriptDom.type = 'text/javascript';

scriptDom.onload = scriptDom.onreadystatechange = function() {
  /**
   *  readyState 表示当前状态,loaded 表示已经加载完成,complete 表示已经执行完成
   *  这里的this指向的是script元素
   */
  if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {
    window.wx.ready(() => {
      // 注入应用的权限
      ajax.get('balabalabala').then(cof => {
        const confObj = cof.data.data || {};
        window.wx.agentConfig({
          ...confObj,
          success: function(res) {},
          fail: function(res) {}
        });
      });
    });
    // Handle memory leak in IE => 释放内存,防止内存泄漏
    script.onload = script.onreadystatechange = null;
  }
};

const locationUrl = encodeURIComponent(window.location.href.split('#')[0]);
const url = `/ins-api/wechat/jsapi/signature?url=${locationUrl}`;
scriptDom.src = url;
headDom.appendChild(scriptDom);

7. 获取外部联系人userId

获取当前外部联 系人userid

ps : 需要在权限中的jsApiList配置getCurExternalContact

wx.invoke('getCurExternalContact', {}, function(res){
  if(res.err_msg == "getCurExternalContact:ok"){
    userId  = res.userId ; //返回当前外部联系人userId
  }else {
    //错误处理
  }
});

不过需要在注入应用权限的成功回调中进行操作 

window.wx.agentConfig({
  ...confObj,
  success: function(res) {
    // 获取外部联系人userId
    window.wx.invoke('getCurExternalContact', {}, function(res) {
      if (res.err_msg == 'getCurExternalContact:ok') {

        // 返回当前外部联系人userId
        const userId = res.userId; 
        
      } else {
        console.log('获取外部联系人userId失败');
      }
    });
  },
  fail: function(res) {
    console.log('agentConfig fail', res);
  }
});

8. 获取用户信息

通过传入code和外部联系人userid给后端

getInsToken() {
  if (!this.userId) {
    this.$message({
      msg: '获取当前外部联系人id失败'
    });
    return false;
  }
  const response = await axios.get('xxx', {
    params: {
      // 地址栏获取的code
      code: this.code,
      // 外部联系人id
      userId: this.userId
    }
  });
  const data = response.data.data || {};
  if (!data.token) {
    this.description = '请先在后台注册账号';
    return false;
  }
  window.localStorage.setItem('SESSIONID', data.token);
  window.localStorage.setItem('customerId', data.customerId);
  window.localStorage.setItem('externalUserId', this.userId);
  window.localStorage.setItem('userName', data.userName);
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值