thumbnail
本文是为了分享我在开发微信公众号网页授权登录时使用到的一段js,以及在使用vue开发公众号网页时遇到的问题。
SCOTT Studio

准备工作

在本地开发时,你可以先申请一个 测试公众号,并且将JS接口安全域名设置为 127.0.0.1 申请地址

找到网页授权获取用户信息这一项,点击修改之后填入 127.0.0.1

特别说明

这里需要配置的是ip或者域名,切记不要添加 http:// 或者 https://

实现逻辑

第一步:用户同意授权,获取 code 。如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE

第二步:通过 code 换取网页授权 access_token

第三步:刷新 access_token(如果需要)

第四步:拉取用户信息(需scope为 snsapi_userinfo)

微信官方参考文档

以下是封装后的代码

import router from "../routerConfig";
import { axiosPost } from "../api";
/*微信登录相关  start*/
const APP_ID = 'xxx'
//方法:用来判断是否是微信内置的浏览器
export function isWechat() {
  return String(navigator.userAgent.toLowerCase().match(/MicroMessenger/i)) === "micromessenger";
}
//方法:用来提取code
export function getUrlCode(name) {
  return (
    decodeURIComponent(
      (new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec(
        location.href
      ) || [, ""])[1].replace(/\+/g, "%20")
    ) || null
  );
}

//检查浏览器地址栏中微信接口返回的code
export function checkWeChatCode() {
  // 如果没有code,则跳转到微信授权页面
  let code = getUrlCode('code')
  if (code) {
    getOpenidAndUserinfo(code)
  } else {
    getWeChatCode()
  }
}
//请求微信接口,用来获取code
export function getWeChatCode() {
  const local = encodeURIComponent(window.location.href); //获取当前页面地址作为回调地址
  let appid = APP_ID
  //通过微信官方接口获取code之后,会重新刷新设置的回调地址【redirect_uri】
  window.location.href =
    "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" +
    appid +
    "&redirect_uri=" +
    local +
    "&response_type=code&scope=snsapi_base&state=" +
    encodeURIComponent(
      JSON.stringify({
        p: "/auth"
      })) + "#wechat_redirect";
}
//把code传递给后台接口,静默登录
export function getOpenidAndUserinfo(code) {
  axiosPost('/pWechatUser/loginByCode', {
    code
  }).then(async ({ retData }) => {
    if (retData.retCode === 100) {
      // 用户不存在,创建用户
      showToast({ message: '当前微信未绑定用户,正在跳转到登录页面', wordBreak: 'break-all' })
      setTimeout(() => {
        router.push(`/login/${retData.retMessage}`)
      }, 1000)
    } else {
      localStorage.setItem('token', retData)
      router.replace({
        path: '/home'
      })

      const { retData: userinfo } = await axiosPost('/pWechatUser/getUserInfo')
      localStorage.setItem('userInfo', JSON.stringify(userinfo))
    }
  })
}

本地开发注意事项

在本地调试时,你需要将你的项目开启使用ip访问,例如 http://127.0.0.1:5173 而不是 http://localhost:5173  

开启方法以vite为例:

export default defineConfig({
  base: './',
  server: {
    // 开启ip访问
    host: "0.0.0.0",
  },
}

vue-router hash模式问题

vue-router默认hash模式下,页面的url都带有#,但微信授权的回调地址不能有#,所以要进行一些处理

// 在配置授权链接时,先传入回调地址的路由path
export function getWeChatCode() {
  const local = encodeURIComponent(window.location.href); //获取当前页面地址作为回调地址
  let appid = APP_ID
  //通过微信官方接口获取code之后,会重新刷新设置的回调地址【redirect_uri】
  window.location.href =
    "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" +
    appid +
    "&redirect_uri=" +
    local +
    "&response_type=code&scope=snsapi_base&state=" +
    encodeURIComponent(
      JSON.stringify({
        p: "/auth"
      })) + "#wechat_redirect";
}

然后在vue-router的路由守卫中添加如下代码


router.beforeEach((to, from) => {
  if (replaceWechatRedirectUri()) return false;
});
function getQueryVariable(variable) {
  const query = window.location.search.substring(1);
  const vars = query.split('&');
  for (let i = 0; i < vars.length; i++) {
    const pair = vars[i].split('=');
    if (pair[0] === variable) {
      return pair[1];
    }
  }
  return (false);
}
/**
 * 处理微信授权回调redirect_uri
 */
function replaceWechatRedirectUri() {
  const w = location.href.indexOf('?');
  const j = location.href.indexOf('#');
  if (w !== -1 && j > w && getQueryVariable('state')) {
    const state = getQueryVariable('state').split('#')[0];
    const redirect_path = JSON.parse(decodeURIComponent(state)).p;
    const url =
      location.origin +
      '/[多级目录路径]/#' +
      redirect_path +
      `?code=${getQueryVariable('code')}&state=${state}`;
    location.replace(url);
    return true;
  }

这样在授权后回到我们的应用时,就不会出现类似 https://xxx.com/auth?code=xxxxxx#/auth 这样的路径了