前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vue的hash路由微信授权方法

vue的hash路由微信授权方法

原创
作者头像
治电小白菜
修改2021-12-14 19:05:11
2.2K1
修改2021-12-14 19:05:11
举报
文章被收录于专栏:技术综合技术综合

示例代码: klren0312/wechatVueHash (github.com)

1. 官方文档步骤

1 第一步:用户同意授权,获取code

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

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

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

5 附:检验授权凭证(access_token)是否有效

2. 问题

当使用vue的hash路由时, 微信授权重定向到前端时, 会把路由放到url最后, 例如

代码语言:txt
复制
https://open.weixin.qq.com/connect/oauth2/authorize?appid=yourappid&redirect\_uri=https%3A%2F%2Fxx.xx.xx%2Fwechat&response\_type=code&scope=snsapi\_base&state=wechat&connect\_redirect=1#wechat\_redirect

会变成

https://xx.xx.xx/wechat/?code=091v5v000CeBWM1bGz2005y2Sd3v5v0q&state=wechat#/codePage
hash路由问题
hash路由问题

3. 处理方法

1) 方法一

在路由拦截器中截取#/后的路由, 重新拼接成正确url, 并使用location.href进行跳转

如果想带参, 可以直接放在路由后面或者放在state里面

带参
带参

**注意**: redirect\_uristate都得使用encodeURIComponent进行编码

当然我们得拿code 去后台请求openId等参数进行业务开发

路由拦截器中进行路由拼接与code获取请求接口例子(本例子页面参数是从state中获取)

代码语言:txt
复制
router.beforeEach(async (to, from, next) => {

  const href = window.location.href

  if (href.indexOf('/?code') > -1) {

    const urlArr = href.split('/?')

    const leftUrl = urlArr[0] + '/#/'

    const rightUrlArr = urlArr[1].split('#/')

    const queryObj = {}

    // 获取code和state参数

    rightUrlArr[0]

      .split('&')

      .map((item) => {

        const splitStr = item.split('=')

        return {

          key: splitStr[0],

          value: splitStr[1],

        }

      })

      .forEach((item) => {

        queryObj[item.key] = item.value

      })

    // 使用微信code请求后台接口拿openId等你业务参数

    getOpenId(queryObj.code)

      .then((res) => res.json())

      .then((res) => {

        if (res.code === 0) {

          // 解码state参数

          const state = decodeURIComponent(queryObj.state)

          // 拼接url, 跳转

          location.href = `${leftUrl}${rightUrlArr[1]}?openid=${res.openid}&state=${state}`

        } else {

          location.href = leftUrl + 'login'

        }

      })

      .catch(() => {

        location.href = leftUrl + 'login'

      })

  } else {

    next()

  }

})

2) 方法二

授权回调后端接口, 后端获取微信的code重定向给前端, 前端拿url中的code参数再请求后端接口获取openId等

流程
流程
代码语言:txt
复制
# 设置为后台接口地址

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxd5be0fe8e3c48877&redirect\_uri=https%3A%2F%2Fxx.xx.xx%2Fapi%2FgetCode&response\_type=code&scope=snsapi\_base&state=wechat&connect\_redirect=1#wechat\_redirect



# 最后跳转地址

https://xx.xx.xx/wechat/#/codePage?code=001sMjFa1F7uhC0lncJa1jHXCs3sMjFa

后端nodejs示例代码

代码语言:txt
复制
const got = require('got')

const express = require('express')

const bodyParser = require('body-parser')

const ioredis = require('ioredis')

const redis = new ioredis()

const app = express()

app.use('/static', express.static('public'))

app.use(bodyParser.json())

app.use(bodyParser.urlencoded({ extended: false }))



const appID = ''

const appsecret = ''



const BASEURL = encodeURIComponent('https://xx.xx.xx/wechat')



const BASEURL2 = encodeURIComponent('https://xx.xx.xx/api/getCode')



//设置所有路由无限制访问,不需要跨域

app.all('\*', function(req, res, next) {

  res.header('Access-Control-Allow-Origin', '\*')

  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept')

  res.header('Access-Control-Allow-Methods', '\*')

  next()

})



const SERVERURL = '/api'

// 微信域名校验

app.get(SERVERURL + '/wechat', function(req, res) {

  const { signature, timestamp, nonce, echostr } = req.query

  console.log(req.query)

  const token = 'zzes'

  jsSHA = require('jssha')

  const arr = [token, timestamp, nonce].sort()

  shaObj = new jsSHA(arr.join(''), 'TEXT')

  const currentSign = shaObj.getHash('SHA-1', 'HEX')

  if (currentSign === signature) {

    res.send(echostr)

  } else {

    res.send('')

  }

})



// 获取用户openId

app.post(SERVERURL + '/getOpenId', function(req, res) {

  const { code } = req.body

  const url = `https://api.weixin.qq.com/sns/oauth2/access\_token?appid=${appID}&secret=${appsecret}&code=${code}&grant\_type=authorization\_code`

  got(url).then(data => {

    const result = JSON.parse(data.body)

    if (result?.openid) {

      console.log('openid:' + result.openid)

      res.send({

        code: 0,

        binding: true,

        openid: result.openid

      })

    } else {

      console.log('err', result)

      res.send({

        code: result.errcode,

        binding: false,

        openid: '',

        msg: result.errmsg

      })

    }

  }).catch(err => {

    res.send({

      code: -1,

      binding: false,

      openid: '',

      msg: err.message

    })

  })

})



// 后端拿code, 这里授权域名得配后台的域名

app.get(SERVERURL + '/getCode', async function(req, res) {

  const { code } = req.query

  console.log(req.query)

  res.redirect(`${decodeURIComponent(BASEURL)}/#/codePage?code=${code}`)

})



// 发送模板消息

app.get(SERVERURL + '/sendMsg', async function(req, res) {

  const { openid } = req.query

  const result = await sendTemplateMsg(openid)

  res.send(result)

})



//端口:18888

var server = app.listen(28848, function() {

  console.log("127.0.0.1:28848")

})



// 创建菜单

setWechatMenu()

async function setWechatMenu() {

  const state = `wechat`

  const menu = {

    button: [

      {

        name: '菜单',

        sub\_button: [

          {    

            type:'view',

            name:'测试一',

            url:`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appID}&redirect\_uri=${BASEURL}&response\_type=code&scope=snsapi\_base&state=${state}#wechat\_redirect`

          },

          {    

            type:'view',

            name:'测试二',

            url:`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appID}&redirect\_uri=${BASEURL}&response\_type=code&scope=snsapi\_base&state=${state}#wechat\_redirect`

          },

          {    

            type:'view',

            name:'测试',

            url:`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appID}&redirect\_uri=${BASEURL2}&response\_type=code&scope=snsapi\_base&state=${state}#wechat\_redirect`

          }

        ]

      }

    ]

  }

  let accessToken = await redis.get('access\_token')

  if (!accessToken) {

    accessToken = await getAccessToken()

  }

  got({

    url: `https://api.weixin.qq.com/cgi-bin/menu/create?access\_token=${accessToken}`,

    method: 'POST',

    body: JSON.stringify(menu)

  }).then(data => {

    const result = JSON.parse(data.body)

    console.log('菜单', result)

  })

}



/\*\*

 \* 发送模板消息

 \*/

async function sendTemplateMsg(openid) {

  let accessToken = await redis.get('access\_token')

  if (!accessToken) {

    accessToken = await getAccessToken()

  }

  const state = encodeURIComponent(`wechat&id=${Math.floor(Math.random() \* 100)}`)

  return got({

    url: `https://api.weixin.qq.com/cgi-bin/message/template/send?access\_token=${accessToken}`,

    method: 'POST',

    body: JSON.stringify({

      touser: openid,

      template\_id: '',

      url: `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appID}&redirect\_uri=${BASEURL}&response\_type=code&scope=snsapi\_base&state=${state}#wechat\_redirect`,

      data: {

        time: {

          value: new Date().toLocaleString(),

          color: '#323232'

        },

        content: {

          value: '您有新的消息, 请点击查看',

          color: '#ff0000'

        }

      }

    })

  }).then(data => {

    const result = JSON.parse(data.body)

    return result

  })

}



/\*\*

 \* 获取access\_token

 \*/

function getAccessToken() {

  return got(`https://api.weixin.qq.com/cgi-bin/token?grant\_type=client\_credential&appid=${appID}&secret=${appsecret}`)

    .then(data => {

      console.log(data.body)

      const result = JSON.parse(data.body)

      if (result?.access\_token) {

        redis.set('access\_token', result.access\_token, 'EX', result.expires\_in - 60)

        return result.access\_token

      } else {

        console.log('err', result)

        return ''

      }

    })

    .catch(err => {

      console.log(err)

      return ''

    })

}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 官方文档步骤
  • 2. 问题
  • 3. 处理方法
    • 1) 方法一
      • 2) 方法二
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档