第三方网站登录绑定微信、使用微信扫码登录

3,324 阅读5分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

近期开发过程中,有个需求是使用微信扫码登录后台管理系统。跟后端对接相关内容是,登录用户首次登录必须使用账号密码登录,之后需要在个人中心页绑定微信,绑定成功后,在后续的登录操作中,即可实现扫码登录。

毫无疑问,该功能的实现需要参考微信开放平台的API,链接地址是:准备工作 | 微信开放文档。接下来,我会谈一下自己在实现的过程中遇到的问题和整体流程。最初,我是蒙的,服务端首先开始该功能的开发,接口实现之后,将相关事宜告知我,我开始参考API进行实现,看了之后有些了解,当我们老大跟我讲了整体思路,我才真正明白。

首先是二维码的生成,这个是需要前端开发人员去实现的,在这里,我使用的是vue框架,该功能的实现引用了wxlogin组件,使用之前需要安装一下,安装命令:npm install vue-wxlogin --save-dev。引用方式代码如下:

<el-button type="success" @click="bindWechat">绑定微信</el-button>

我需要的效果是点击按钮,弹出二维码:

<div class="login-qr" v-if="bindWechatShow">
    <wxlogin :appid="appid" :scope="scope" :theme='style' :state='state' :redirect_uri="redirect_uri"></wxlogin>
</div>

同时,在data里面需要定义相关参数:

// 微信二维码相关参数
appid: 'wx……',
scope: 'snsapi_login',
state: 'bind',
style: 'black',
redirect_uri: encodeURI('……………………'),

上述代码即可实现二维码图片的展示。

当用户点击确认登录按钮之后,有一个重要的重定向问题,就是参数redirect_uri。重定向之后的结果就是可以获取到state和code,作为前端而言,需要带上这两个参数去请求服务接口。在实现该内容的过程中,我遇到三个问题:

第一个问题是重定向地址该如何填写,下图就是我的重定向地址,我另写了一个页面,即wechat页面,该页面就是一个过渡页面,没有任何内容,会一闪而过。在该页面中,可以写请求接口,页面展示内容为空即可。

第二个问题是该功能模块的实现在本地无法实现测试,我们团队采用了frp,首先普及下frp是什么,FRP 服务可以分配给你一个域名让你本地的web项目提供给外网访问, 特别适合向别人展示你本机的web demo 以及调试一些远程的API (比如微信公众号,企业号的开发)。如此一来,我跟服务端可以进行调试,因此,会发现,重定向的路径配置并不是访问的本地。即便如此,作为前端而言,正常启动本地服务即可,在运行的时候,直接访问上述路径地址即可。而在这之前,我是成功启动了frp。上述重定向地址的参数encodeURI()是编码的意思,该函数可以把字符串作为URI进行编码,如下所示:

document.write(encodeURI("http://www.xxxx.com.cn/My first/"))

输出结果为:

http://www.xxx.com.cn/My%20first/

第三个问题是在启动项目之后,需要登录,此时开始请求服务端接口,但是第一个接口就失败了,报错内容是

跨域问题,和我们的设置有关,前端接口请求的是一个地址,但是经内网穿透之后,访问的是另一个地址,这就无法走通。因此我们统一了域名,成功实现登录。

解决上述问题之后,开始进行扫码绑定微信,在这一过程中又遇到几个问题。

第一个问题,我点击确认登录之后,重定向之后,我拿到了code和state,同时我需要带着code与state去访问接口,此时报错。原因后台需要我传的token,但此时是从重定向之后请求的接口,我已经拿不到token,因此传过去的Authorization是空的,前后台不一致报错,后台做了处理,成功了。

第二个问题,我绑定微信之后,请求接口结束拿到响应结果,无论是成功还是失败,都想要重新跳转到该页面,达到刷新页面的结果。但是,此时,我已经没有了token,没有权限的我只能跳转到不需要权限的页面,做不了其他操作。该问题的解决方式是,在用户绑定微信成功的同时,做一个隐形的登录操作,去问后台更新token,从而可以继续请求其他接口。

在实现隐形登录操作的过程中,由于我的登录数据采用了vuex状态管理器,在该操作时想通过该方式将我所需要传递的数据进行传递,包括用户登录信息及重要的token,最初我使用store.state.user及store.state.token,效果或者说功能实现了,但是报错,报错信息如下: image.png 第一次遇到该类型的报错,经排查发现是这里的问题,触犯了vuex使用过程中的严格规定。其实在最初的时候,认为是vuex严格模式的问题,当然,也确实有一点关系,具体使用方式见官网:严格模式 | Vuex

该报错的主要原因是直接修改store中的状态了,vuex中明确规定,改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation,基于此,我去通过commit提交。当时理解不到位,不知道该怎么拿到commit,其实去打印会发现,commit在哪里。

首先我打印了该页面中拿到的store,如图所示:

image.png

同时打印了this.$store,包含参数如图所示:

image.png

如此可以拿到任何我需要的参数,因此上述问题的解决方式是改用如下代码:

// 必须使用commit触发状态变更,提交mutation,通过提交 mutation 的方式,而非直接改变 store.state.token,是因为我们想要更明确地追踪到状态的变化
this.$store.commit(types.UPDATE_STAFF, response.data.staffUser)
this.$store.commit(types.UPDATE_TOKEN, response.data.token)

第三个问题,若是绑定微信成功,在登录页面,扫描二维码成功之后的登录操作,是与使用账号密码登录方式一样的。这一点是我个人的理解问题,最初想成了扫描完毕,请求接口,成功即可实现登录,其实不然。依然需要使用action进一步更新mutations。

// 微信扫码登录
  [types.STAFF_WX_LOGIN] ({ commit }, wxLoginInfo) {
    let loginParams = {
      'appId': wxLoginInfo.appId,
      'code': wxLoginInfo.code.trim(),
      'state': wxLoginInfo.state.trim(),
      'ip': wxLoginInfo.ip
    }
    return new Promise((resolve, reject) => {
      StaffAPI.loginWechat(loginParams).then(response => {
        const data = response.data
        commit(types.UPDATE_STAFF, data.staffUser)
        commit(types.UPDATE_TOKEN, data.token)
        resolve(response)
      }).catch(error => {
        reject(error)
      })
    })
  }

目前为止,该功能已经基本实现,该功能牵扯到的相关技术我会进一步去学习,加深理解。