试图教会你实现网站微信授权登录

599 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

现在很多网站都有第三方登录,网页中的微信扫码登录也已经是很常见的功能了,下面就介绍一下网页微信扫码授权登录,咱们前端得如何实现,以及可能遇到的问题和解决方案~


扫码类型

网页中的微信的扫码授权可以分成两种:

  • 整体展示:扫码界面

    • 这类的会直接跳转到微信官方提供的扫码界面,从url也可以看出来。这中从前端的实现来说是比较容易的一种,但从用户的体验来说并不是很好,本文就不介绍这种了。

    • image.png

  • 局部展示:弹窗扫码

    • 这类扫码是以弹窗局部显示,从用户体验来说是比上面一种好的,这种的实现主要是通过iframe,也是后续我介绍的方案。
    • image.png

准备工作

在进行网页微信授权登录接入之前,我们需要在微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的 AppID 和AppSecret,申请微信登录且通过审核后,可开始接入流程。官方文档

实现

  1. 首先我们需要将微信官方提供的JS文件( 文件链接)引入当前页面内

    const loadingJSFile = function () {
      let scriptDom = document.createElement('script'); 
      scriptDom.type = 'text/javascript';
      scriptDom.src = 'https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js';
      document.body.appendChild(scriptDom);
    };
    loadingJSFile();
    
  2. 当我们点击触发弹窗时,首先需要将弹窗绑定的变量设为true,然后再nextTick内来处理展示微信扫码界面, 伪代码如下

    import { ref, nextTick } from 'vue';
    let isBindWeChat = ref<boolean>(false);
    const showConfirm = async () => {
      isBindWeChat.value = true;
      nextTick(() => {  
        let wxObject = new WxLogin({
          id: 'login-div', //展示扫码界面的容器
          appid, //应用唯一标识,在微信开放平台提交应用审核通过后获得
          scope: 'snsapi_login', //网页应用目前仅填写snsapi_login即可
          redirect_uri, //重定向地址, 又公众号配置的回调地址,只能配置一个!
          state , //用于保持请求和回调的状态,授权请求后原样带回给第三方。
          style: 'black',//提供"black"、"white"可选,默认为黑色文字描述
        });
      }
    };
    showConfirm();
    
  3. 至此,唤醒微信扫码授权界面的功能,咱们前端就已经做完了,切图仔的工作就是轻松(手动狗头保命),当然后续扫码成功后的流程需要你们自己与后端配合实现。下图就是唤醒微信扫码的效果:

image.png

问题

当你没有问题的时候,问题就来了~

从Chrome 64版本开始,浏览器将阻止任何来自第三方框架的自动重定向。

其他大多数浏览器,默认也是会阻止网页的弹窗和不同域名的重定向功能的:

image.png

而我们使用的iframe实现的弹窗扫码授权,就是会重定向网页,当公众号配置的回调地址跟我们当前网页的地址不是同一个域名时,扫码成功后的重定向就会被浏览器默认拦截,导致我们扫码成功后页面没有反应

image.png

解决

了解

实现内展示的图,我们可以知道弹窗是通过iframe的方法嵌入的,因此我们需要去了解一下iframe

iframe默认情况下:采用默认的安全策略。

  • iframe的页面将会被当做一个独自的源,同时不能提交表单,以及执行javascript脚本,也不能让包含iframe的父页面导航到其他地方,所有的插件,如flash,applet等也全部不能起作用。
  • 简单说iframe就只剩下一个展示的功能,正如他的名字一样,所有的内容都被放入了一个单独的沙盒。

解决的属性

sendbox包含的属性及作用:

  • allow-forms 允许进行提交表单
  • allow-scripts 运行执行脚本
  • allow-same-origin 允许同域请求,比如ajax,storage
  • allow-top-navigation 允许iframe能够主导window.top进行页面跳转
  • allow-popups 允许iframe中弹出新窗口,比如,window.open,target=”_blank”
  • allow-pointer-lock 在iframe中可以锁定鼠标,主要和鼠标锁定有关

iframe默认是没有设置sendbox属性的!因此我们只需要设置上该属性,就可以阻止浏览器默认拦截我们的扫码授权重定向了!!!

以下是伪代码:

let wxObject = new WxLogin({
  id: 'login_div',
  appid: data.appid,
  scope: 'snsapi_login',
  redirect_uri: data.redirect_url,
  state: data.state,
  style: 'black',
  href: '',
});
//当new WxLogin后,iframe已经被嵌入到我们指定的id容器内了
let wxIframeEle = document.querySelector('#login-div iframe');
// 对嵌入的微信iframe设置以下属性,可以阻止浏览器默认对重定向的拦截
wxIframeEle.setAttribute(
  'sandbox',
  'allow-top-navigation allow-same-origin allow-scripts',
);

其他问题

通过上述给微信扫码的iframe设置上sendbox属性后,正常就可以了。

但!

我在开发服测试没问题,不会被浏览器拦截了。可测试一拉一部署,到测试服就G了(哭了~~~)。

于是我立马登录测试服尝试,果然不行...

经过一大堆搜索引擎的搜索链接,最后找到了一个解决办法:在微信生成的iframe的src链接后面拼接上self_redirect=true即可

wxIframeEle.src = `${wxIframeEle.src}&self_redirect=true`;

总结

至此微信扫码授权也算完成了~!

以下是微信文档介绍扫码授权的图例

image.png

微信扫码授权流程大致有三,如下:

  • 前端向后端拿到公众号的配置数据(亦可写死),唤醒微信扫码弹窗
  • 用户扫码成功,微信平台会重定向网页到公众号配置的回调地址(可能是后端的一个接口路径,亦可是前端的一个界面地址)
  • 重定向到回调地址的界面或接口后,在这里处理扫码后的逻辑(前后端商量确定如何实现)