【微信开发】微信网页授权+创建测试账号

1,869 阅读5分钟

很少写微信H5的项目,最近做了一个微信公众号的项目,想整理记录一下开发过程中遇到的一些问题,同时也顺便开启养成写文章的习惯,希望能让自己做出些改变,成长的更好。

废话不多说,进入正题。

微信公众号静默授权

在微信中访问第三方网页时,公众号可以通过微信网页授权机制来获取用户的基本信息,进而实现业务逻辑,无需用户进行额外的登录注册操作。

开发前准备

在开发前,需要有一个授权回调的域名,也就是h5网页的域名和接口的域名。

线上的话,这个需要在公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,设置授权回调域名,如www.qq.com

创建测试公众号

如果是测试环境,可以创建一个测试账号,大概过程如下:

  1. 进入微信公众帐号测试号申请系统,扫码登录
  2. 以下页面中,⚠️ 测试环境接口验证token 的URL和Token均由服务端同学提供;js接口安全域名,只输入前端页面域名,形式如www.qq.com,不用加协议http前缀
  3. 在“体验接口权限表” - “网页服务” - “网页帐号” - “网页授权获取用户基本信息” - 点击后面的“修改”按钮,出现如下弹窗,配置授权回调页面的域名 只输入域名,形式如www.qq.com
  4. 参考本地调试微信网页授权这篇,将hosts配置和nginx配置改成以上配置的测试域名。

网页授权的流程主要分为4步:

  1. 引导用户进入授权页面同意授权,获取code
  2. 通过code换取网页授权access_token(与基础支持中的access_token不同)
  3. 如果需要,开发者可以刷新网页授权access_token,避免过期
  4. 通过网页授权access_token和openid获取用户基本信息

⚠️ ️️关于网页授权access_token和普通access_token的区别:

微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息;

其他微信接口,需要通过基础支持中的“获取access_token”接口来获取到的普通access_token调用。

一、先简单封装一个微信授权的方法,后面可以直接调用该方法走授权的逻辑
// @/utils/wxAuth.js

// appid - 公众号的唯一标识
// redirect_uri - 授权后重定向的回调URL地址, 需要编码
// state - 授权重定向后会带上state参数,可以填写a-zA-Z0-9的参数值,最多128字节,这里我默认设置的为1
// response_type - 返回类型,固定为code
// scope - 应用授权作用域,主要分两种:snsapi_base & snsapi_userinfo
function wechatAuth(redirect_url = window.location.href, state = 1) {
  const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent(redirect_url)}&response_type=code&scope=snsapi_userinfo&state=${state}#wechat_redirect`;
  window.location.href = authUrl;
}
export default wechatAuth;

⚠️ 这里讲一下scope两种情况的区别,可以根据需要选择:

  1. 以snsapi_base为scope发起的网页授权,不弹出授权页面,静默授权后直接自动跳转到回调页,该方式只能获取用户的openid。用户感知的就是直接进入了回调页(往往是业务页面)。
  2. 以snsapi_userinfo为scope发起的网页授权,弹出授权页面,需要用户手动同意授权,无论是否关注公众号,只要用户授权,即可获取该用户的基本信息,通过openid可以拿到用户的昵称、性别、所在地。
二、router.js,在beforeEach全局钩子函数中,判断是否需要用户授权
// @/utils/index.js
// 判断是否是微信浏览器
function isWeChat() {
  const ua = window.navigator.userAgent.toLowerCase();
  // eslint-disable-next-line eqeqeq
  if (ua.match(/MicroMessenger/i) == 'micromessenger') {
    return true;
  }
  return false;
}
export default { isWeChat };


// router.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import index from '@/views/index/index.vue';
import { isWeChat } from '@/utils/';
import wechatAuth from '@/utils/wxAuth.js';
import { wechatLogin } from '@/api/';
import { Toast } from 'vant';


Vue.use(VueRouter);

// 页面路由
const routes = [
  {
    path: '/',
    component: index,
    meta: {
      title: '首页',
    },
  }, 
  ...
];

const router = new VueRouter({
  mode: 'history',
  routes,
});

// 在全局钩子函数beforeEach中,判断是否进行微信授权
router.beforeEach(async (to, from, next) => {
  // to: Route: 即将要进入的目标 路由对象
  // from: Route: 当前导航正要离开的路由
  // next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
  const isweChat = isWeChat();
  // 如果不是在微信浏览器打开页面,提示用户微信打开
  if (!isweChat) {
    Toast('请在微信中打开');
    return;
  }
  // 用户信息保存在了vuex中,如果没有userId,需要用户授权拿到code,然后传参给接口,获取用户userId
  if (!store.getters.userId) {
    // 获取目标路由上的code参数
    const { code } = to.query;
    // 如果URL上没有code,说明用户还没有授权,调用上面封装好的方法,进行微信授权
    if (!code || code === 'undefined') {
       // 进入授权之前,先保存一下未授权的页面地址,后面会用到
      window.sessionStorage.setItem('curPageUrl', window.location.href);
      // 调用上面封装的微信授权方法
      wechatAuth();
      return;
    }
    // 微信授权后,会直接跳转redirect_uri并带上code参数,如果回调URL上有code参数,说明用户授权过了,已经进入了授权后的回调页,这个时候,将URL上的code作为参数,传递给接口,去获取用户的userId
    // ⚠️ ️wechatLogin 是我们项目中用到的一个接口,接口会根据code返回用户的userId
    await wechatLogin({
      code,
      // 因为项目中暂时未用到分享功能,所以inviterId传空即可
      inviterId: '',
    }).then((res) => {
      // 接口成功的回调中,保存接口返回的用户信息(userId和token)
      store.commit('SET_USER_INFO', res.data);
    }).catch(() => {
      // 授权后的code只能使用一次,所以在授权过的带code的回调页上刷新页面,就会导致接口调用失败。当然,接口本身也可能因为其他原因而失败。
      // 如果调用接口失败,需要再次进行授权,拿到一个新的code。如果是授权过的页面本身是有code的,重复走授权会在URL后面添加多个code,取code的时候就有问题了,这个时候,我们就用到前面没有code时,保存的那个url地址啦
      const url = window.sessionStorage.getItem('curPageUrl');
      wechatAuth(url);
    });
  }
  // 拿到用户的userId后,就可以正常调用next()来resolve这个钩子函数了。
  if (store.getters.userId) {
    next();
  }
});

关于微信授权的更多内容详见:微信官方文档-微信网页授权