React 实现企微扫码登录

2,605 阅读5分钟

需求背景

公司的内部基建应用众多,为便于全司员工内部的使用方便,所以单独将登录系统抽出来作为一个单独的应用,统一基建平台下的所有应用的登录风格,一个应用登录成功之后,这个登录系统下属的所有应用全部默认登录成功。这个方式叫做SSO登录。 SSO登录介绍:

SSO单点登录

单点登录(SSO)

单点登录(SSO)看这一篇就够了

部分应用未接入这个登录系统之前,拥有自己的登录方式,包含企微的扫码登录,现在为了兼容所有应用,以及用户能够方便使用登录系统,在原有基础之上增加企微扫码登录功能。

企微扫码授权登录官方文档

实现方案

企微登录流程图

image.png

这个流程图就是整个登录行为的全过程,前端所需要做的就是构造登录链接->跳转登录链接/嵌入登录链接到页面里->展示登录链接->用户扫码点击登录->后端鉴权控制跳转至重定向页面或者登录失败页面

步骤:

1.开启网页授权登录:登录 企业管理端后台->进入需要开启的自建应用->点击 “企业微信授权登录”,进入如下页面 image.png 然后点击 "设置授权回调域",输入回调域名,点击“保存”。

要求配置的授权回调域,必须与访问链接的域名完全一致。举个例子:

配置域名是否正确原因
mail.qq.com:8080correct配置域名与访问域名完全一致
email.qq.comerror配置域名必须与访问域名完全一致
support.mail.qq.comerror配置域名必须与访问域名完全一致
*.qq.comerror不支持泛域名设置
mail.qq.comerror配置域名必须与访问域名完全一致,包括端口号
mail.qq.com:8080error不包括协议头

第一步:实现二维码登录样式

在原本账号密码登录的界面基础上,加上二维码的交互,值得一提的是,右上角的样式实现,放一个正方形盒子放二维码图标,然后再用border的那一套画出一个三角形盖住,就有了这种效果。这里的样式借鉴了其他网站,稍微做了放大缩小的效果。其次,鼠标放上去之后颜色变化,这个图标是直接从iconfont网站上找的,你下载下来之后使用会发现不变色,原因是iconfont上的图标默认是带了颜色的,svg标签的属性上面有个fill属性是规定颜色的,可以在iconfont中统一去除再用,就可以跟字体一样设置颜色了。

image.png

第二步:给二维码图标那边的盒子增加点击事件,切换到二维码容器界面

容器样式代码:

<div>
 <div className="wx-login">
    {qrcodeVisible && (
      <div className="wx-box">
        <Select
          defaultValue={currentCompany.companyIdDisplayName || undefined}
          style={{ width: 200 }}
          onChange={(value) => {
            const newCompany = JSON.parse(value);
            localStorage.setItem(
              'SSO_USER_COMPANY',
              JSON.stringify(newCompany.companyId)
            );
            initQrcode(newCompany);
          }}
        >
          {companyList.length > 0
            && companyList.map((item) => {
              return (
                <Option key={item.cropId} value={JSON.stringify(item)}>
                  {item.companyIdDisplayName}
                </Option>
              );
            })}
        </Select>
      </div>
    )}
    <div id="wx_reg" className={qrcodeVisible ? '' : 'hidden'} />
  </div>
  
  
  {isShowQrcode && (
    <div className="toggle-icon" onClick={toggleLogin}>
      {qrcodeVisible ? (
        <i className="iconfont icon-diannao" />
      ) : (
        <i className="iconfont icon-erweima" />
      )}
      <div className="cover" />
    </div>
  )}
</div>

image.png

第三步:在切换到二维码登录界面的同时,调用企微的sdk,实例化一个二维码容器

引入企微sdk

可以直接在打包出口的html文件的Link中直接引入

image.png

或者:

image.png

点击事件之后实例化二维码容器

  • 这里有个坑,引入sdk之后,vue跟react中,api挂载的地方不一样
  • vue可以直接使用,react中是挂载在window上面的
  • 这个实例化的对象id是放置企微二维码的盒子容器id
  • 如果是单个应用的登录系统,appid跟agentid是公司跟企微服务台那边申请的固定的id,我这里是要支持不同公司的不同应用,所以上面做了一个下拉框用于选择公司,下拉框里有不同公司,不同公司的数据里包含了appid,agentid,每次切换重新init实例化,就可以生成新的二维码
  • 根据sso登录原理,从子应用跳转到这个页面的时候,url中带着应用地址以及target,在此基础上向后端发请求,后端可以识别当前应用,然后返回对应的公司列表,包含appid,以及agentid。
  • 重定向地址为后端约定,本项目是拼接子应用的地址加/verifyWechatCode
  • state中存放后端需要的参数,用于鉴权+跳转,这里的参数需要进行base64转码
  • 这个二维码生成,扫码之后会生成一个base64转码的链接
  /**
   * @description: react初始化二维码
   * @param {*} company
   * @return {*}
   */
  const initQrcode = (company) => {
    const obj = new window.WwLogin({
      id: 'wx_reg', // 登录页面显示二维码的容器id
      appid: company.cropId, // 企业微信的CorpID,在企业微信管理端查看
      agentid: company.wechatAppId, // 授权方的网页应用id,在具体的网页应用中查看
      redirect_uri: `${window.location.protocol}//${window.location.host}/verifyWechatCode`, // 重定向地址
      state: window.btoa(
        JSON.stringify({
          companyId: company.companyId,
          service,
          target,
          cropId: company.cropId,
          callbackDomain: window.location.host,
          wechatAppId: company.wechatAppId,
        })
      ), // 额外向后端传的值
      lang: 'zh',
    });
  };
  
    /**
   * @description: vue初始化二维码
   * @param {*} company
   * @return {*}
   */
  const initQrcode = (company) => {
    const obj = new WwLogin({
      id: 'wx_reg', // 登录页面显示二维码的容器id
      appid: company.cropId, // 企业微信的CorpID,在企业微信管理端查看
      agentid: company.wechatAppId, // 授权方的网页应用id,在具体的网页应用中查看
      redirect_uri: `${window.location.protocol}//${window.location.host}/verifyWechatCode`, // 重定向地址
      state: window.btoa(
        JSON.stringify({
          companyId: company.companyId,
          service,
          target,
          cropId: company.cropId,
          callbackDomain: window.location.host,
          wechatAppId: company.wechatAppId,
        })
      ), // 额外向后端传的值
      lang: 'zh',
    });
  };

第四步:扫码成功之后,在企微端确认登录,生成链接跳转,后端在此过程中鉴权并决定是否跳转对应子应用,成功或失败

sso机制下的登录系统,大多是由后端进行鉴权以及跳转,前端的事很少

实例化登录对象的方式是嵌入在页面中的,还有一种方式是同样的根据appid跟agentid生成链接,跳转到第三方页面生成二维码:

image.png