vue微信授权登录(亲测)


准备:
一、微信公众平台测试帐号申请
1、打开微信公众平台测试帐号申请地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
通过微信扫一扫授权就能进入到测试号管理页面。

二、设置授权域名

在测试号管理页面,需要修改两个地方

第一个:将地址换成外网访问地址:

vue 微信网页授权登录demo vue实现微信授权登录_微信

第二个**(此时不需要前面的http://)**:
如果报redirect_uri参数错误,可检查这步是否去除前面的http://

vue 微信网页授权登录demo vue实现微信授权登录_openid_02

vue 微信网页授权登录demo vue实现微信授权登录_vue_03

除了修改上面两个地方以外,作为测试号,还需要将当前页面前面的测试号信息发给后台

vue 微信网页授权登录demo vue实现微信授权登录_vue_04

现在,前台的基本配置已经完成了。



微信网页授权文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842

由微信的官方文档得知,授权登陆共分为四步:

1 第一步:用户同意授权,获取code
2 第二步:通过code换取网页授权access_token
3 第三步:刷新access_token(如果需要)
4 第四步:拉取用户信息(需scope为 snsapi_userinfo)

其中,第一步由前端来做,第二步前端把code传到后端,后端获取access_token,第三步第四步则需要后端完成。

写代码之前需要明确下需求,整理下思路,先想再写是个好习惯。

我们需要做的是:

1、前端在需要获取用户信息的页面调起登录,某些页面不需要,比如首页、某些展示静态页。
2、微信返回,前端截取返回url中的code传给后台,并把后台返回的Token存到Cookie和axios的header头中。
3、如果Cookie中已经有Token了,调另一个接口,判断token是否已经过期,过期重新登录。

一、微信授权(history模式/hash模式)

1、history模式下的微信授权登录
查阅Vue Router修改mode 为history 去掉“#/”符号,也需要后台配合改一下,不然页面会404。

mode: "history"

在路由守卫before-each.js的beforeEachHandler中写登录代码

白名单判断:

if ((to.meta && to.meta.needLogin)) {//授权操作

}else {//白名单内不做授权判断,直接next
    next()
  }

第一步:授权,1:

const appid = "wxd49a9705a0c6464a"; // 公众号的唯一标识
 //授权后重定向的回调链接地址, 请使用 encodeURIComponent 对链接进行处理
const redirect_uri = encodeURIComponent(window.location.href.split("?")[0]);
const scope = "snsapi_userinfo"  //弹出授权页面
const urls = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=STATE#wechat_redirect `
window.location.href = urls

参数说明:

vue 微信网页授权登录demo vue实现微信授权登录_vue_05

第二步:授权之后截取url中的code传给后台,2:

var code = to.query.code //History模式直接从url获取code
//前端将code传给后台,并把后台返回的Token存到Cookie和axios的header头中
const result = await commonApi.getUserInfo2({ code: code })
if (result.code == 200) {
    Cookie.set("Token", result.token)
    axios.defaults.headers.common['Token'] = result.token
    next()
 }

第三步:如果Cookie中有Token,3:

// 获取本地token
      const hasToken = Cookies.get("Token");
      if (hasToken) {
        console.log("有token");
        //去 获取用户信息
        next()
      }else{//去执行第一步:授权
      console.log("无token")
      }

2、hash模式下的微信授权登录

微信授权登录验证会把网址中的#号去掉,这样在跳转的时候Vue拿不到Code。所以在第二步做了以下处理

//Vue - router hash模式微信登录授权验证,#号处理
let href = window.location.href;
if (href.includes("code")) {  //url包括 com/?code 证明为从微信跳转回来的
var url = href.substring(0, href.length - 2); //vue自动在末尾加了 #/ 符号,截取去掉
var jingPosit = url.indexOf("?code"); //获取?code位置
var urlLeft = url.substring(0, jingPosit);//url左侧部分
var urlRight = url.substring(jingPosit, url.length); //url右侧部分
console.log(urlLeft + "#/" + urlRight);
window.location.href = urlLeft + "#/" + urlRight;//拼接跳转
}

获取code方式换成:

var code = getQueryString("code");//hash模式获取url中code
function getQueryString(name) {//解析url中的参数
  var arr = (location.hash || "")
    .substr(location.hash.indexOf("?") + 1)
    .replace(/^\#/, "")
    .split("&");
  var params = {};
  for (var i = 0; i < arr.length; i++) {
    var data = arr[i].split("=");
    if (data.length == 2 && data[0] == name) {
      return data[1];
    }
  }
  return null;
}

二、完整代码(hash模式为例,如果改为history模式,去掉相对应代码)

// 页面路由拦截
async function beforeEachHandler(to, from, next) {
  if ((to.meta && to.meta.needLogin)) {
    try {
      // 获取本地token
      const hasToken = Cookies.get("Token");
      if (hasToken) {
        console.log("有token");
        //去 获取用户信息接口
        next()
      } else {
        console.log("无token")
        var code = getQueryString("code");//hash模式获取url中code
        //var code = to.query.code //History 模式从url获取code
        if (code) {//如果存在code,则拿code去后台获取openid拿到用户信息token
          Cookies.set("Token", "dhjshruwy3888384")//没有对接口,token先写死
          next()
          //接口:前端将code传给后台,并把后台返回的Token存到Cookie和axios的header头中
          // const result = await commonApi.getUserInfo2({ code: code })
          // if (result.code == 200) {
          //   sessionStorage.setItem("Token", result.token)
          //   axios.defaults.headers.common['Token'] = result.token
          //   next()
          // }
        } else {//如果不存在code,url中包含code,说明已授权
      //hash模式微信登录授权验证,#号处理(如果在history模式下,这段#号处理if,else可删除)
          let href = window.location.href;
          if (href.includes("code")) {  //url包括 com/?code 证明为从微信跳转回来的
          //vue自动在末尾加了 #/ 符号,截取去掉
          var url = href.substring(0, href.length - 2); 
          var jingPosit = url.indexOf("?code"); //获取?code位置
          var urlLeft = url.substring(0, jingPosit);//url左侧部分
          var urlRight = url.substring(jingPosit, url.length); //url右侧部分
          console.log(urlLeft + "#/" + urlRight);
          window.location.href = urlLeft + "#/" + urlRight;//拼接跳转
        //授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
          const redirect_uri = encodeURIComponent(window.location.href.split("?")[0]);
          //应用授权作用域:snsapi_userinfo(弹出授权页面,可通过openId拿到昵称、性别、所在地。)
          const scope = "snsapi_userinfo"  
          // 应用授权作用域:snsapi_base (不弹出授权页面,直接跳转,只能获取用户openId)
   
          }
        }
      }

    } catch (error) {
      console.error(error, "-------beforeEach错误日志-----")
      next(false)
    }
  } else {
    next()
  }
}

 function getQueryString(name) {//hash模式中需要用到解析url中的参数的函数
  var arr = (location.hash || "")
    .substr(location.hash.indexOf("?") + 1)
    .replace(/^\#/, "")
    .split("&");
  var params = {};
  for (var i = 0; i < arr.length; i++) {
    var data = arr[i].split("=");
    if (data.length == 2 && data[0] == name) {
      return data[1];
    }
  }
  return null;
}

总结:
1、我们只要能拿到code给后端,后端去拿openid,就算授权成功。
2、redirect_uri参数错误,检查下配置域名是否去除http://
3、response_type参数错误,检查redirect_uri 是否 encodeURIComponent
4、hash模式下:授权后重定向的回调链接地址反复授权,需要对#/处理,获取到code
5、如果改为history模式,需要后端配合修改nginx配置,否则部署会出现404

例子在:
手机端vue项目初始化工程模板:
http://47.107.67.231:8888/project-template/mobileInitProject feature/wechat-auth分支下面