做一个兼容微信内置浏览器和普通浏览器的公众号授权页面

关于微信授权,在我没开始搞清楚概念之前我挨个试了3种授权(第三方平台代公众号发起网页授权网站应用微信登录功能以及公众号网页授权),直到第三种才发现是符合当前需求的。

一. 需求

我们已经有了一个已认证的服务号,要开发一个问卷页面,展示用户头像昵称 。需要兼顾 移动设备和pc设备的微信内置浏览器外部浏览器

用户打开以下分享链接或微信扫码可以填写问卷:

图1

场景1:用户通过微信内置浏览器打开(包括直接扫码进入页面)

如果用户通过微信内置浏览器打开,用户授权后,即可填写问卷:

图2

场景2:用户使用pc端微信外部浏览器打开

如果用户通过普通浏览器打开(谷歌、edge等)则展示二维码,让用户通过微信扫码授权:

图3

手机微信扫码授权流程

图4

授权成功后,pc页面成功跳转:

图5

二、实现

通读微信公众号网页授权

1. 如果只是要求微信内置浏览器打开

如果只是要求微信内置浏览器 打开,那么可以直接给用户下面的链接(用户同意授权获取code):

txt 复制代码
https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APPID}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=snsapi_userinfo&forcePopup=true#wechat_redirect

微信打开这个链接后就是上文中图2的效果。

但这个链接在普通浏览器打开会是:

但我们要求普通浏览器也需要能够展示,所以请继续往下看。

2. 分享链接是中转界面

因为不知道用户会不会在微信内置浏览器内打开,所以要做一个中转界面,判断当前浏览器环境,而分享链接跳转的就是这个中转界面。

判断是否在微信浏览器内,如果是则跳转上面的链接,如果不是则展示图3,让用户扫码授权。

js 复制代码
    const inWeChatBrowser = /micromessenger/i.test(navigator?.userAgent?.toLowerCase())
    if (inWeChatBrowser) {
        // 微信内置浏览器
        window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APPID}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=snsapi_userinfo&forcePopup=true#wechat_redirect`
    } else {
        // 微信外部浏览器
        // ...
    }
}

3. 普通浏览器通过手机微信扫码授权进入页面

让用户扫码授权的这个码是后端提供的:

二维码解码后是下面链接:

txt 复制代码
https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&response_type=code&scope=snsapi_userinfo&scene_id=scene_id&forcePopup=True&redirect_uri=手机授权界面(图4)#wechat_redirect

它和微信内置浏览器直接打开的链接有两点不一样:

  1. 内置浏览器直接打开了所以redirect_uri就是问卷的uri,而手机扫码授权的redirect_uri是授权的uri(上文中的图4)。
  2. 手机扫码授权的链接因为要和电脑的码联动,所以后端生成了唯一的scene_id,用于后续pc页面轮询验证扫码结果。

手机授权界面

手机微信扫描后端提供的授权码后,会重定向到手机授权界面,并在链接后面附带code。(此时可以从链接上获取到codescene_id

再将code和scene_id交给后端,后端获取到用户信息进行存储,此时pc端的轮询也会得到结果

三、踩坑

1. 需要配置js安全接口域名

如果报"redirect_uri域名与后台配置的不一致,错误码10003":

那可能是你的js安全接口域名未配置配置错误 ,需登录微信公共平台,打开公众号设置进行配置:

注意点:

  • 记得将校验文件下载到前端项目根目录
  • 只设置域名就好,不用加协议(如 https://www.baidu.com 是不行的, 得是 www.baidu.com

2. hash路由的重定向

如果你的路由模式是hash路由,微信重定向携带的参数会被放在#的前面,如:

js 复制代码
let redirectUri = 'https://www.baidu.com/#/home'

// https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APPID}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=snsapi_userinfo#wechat_redirect

// 以上链接会被重定向到:

// https://www.baidu.com/?code=xxx#/home

这时候用useRoute().query.code是获取不到的,贴上一个方法直接用:

js 复制代码
export function getQueryParamFromURL(url, paramName) {
  try {
      const parsedUrl = new URL(url);
      const paramValue = parsedUrl.searchParams.get(paramName) ?? '';
      return paramValue;
  } catch (error) {
      console.error(`Error processing URL or retrieving the parameter '${paramName}':`, error);
      return '';
  }
}

3. 获取到code后面的步骤交给后端

secret和access_token安全级别非常高,后面的操作应放在服务端完成。

4. 同意授权之前的重定向也会携带code

js 复制代码
// https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APPID}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=snsapi_userinfo&forcePopup=true#wechat_redirect

对于以上链接,文档上说用户同意授权才会发生重定向:

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

但实际上同意授权之前也会发生重定向到redirect_uri并附带code参数,只不过用这个code去获取userInfo获取的是"匿名用户"

例如下面左图中的uri是:

https://xxx/?code=011cXi000jdnsS1eV1100FdqU60cXi0C&state=#/surveyPaper/9cb71a2d

这个code获取的用户信息是匿名用户,获取不到昵称、头像等信息

使用完整服务并同意授权后右图的uri是:

https://xxx/?code=0913cp100ZsttS1jsu300E7DHJ33cp1j&state=#/surveyPaper/9cb71a2d

这个code是可以获取到用户信息的。

5. code been used

微信重定向携带的code,只能使用一次,多次使用会报{"errcode":40163,"errmsg":"code been used, hints: [ req_id: VHfwwa05052279 ]"}

解决方法是后端用redis存第一个code处理的结果,第二个过来去缓存里读,不再向微信发起请求。 这也是大部分的解决思路。参考文章:

juejin.cn/post/686787... blog.csdn.net/limenghua91...

相关推荐
2401_882727571 小时前
低代码配置式组态软件-BY组态
前端·后端·物联网·低代码·前端框架
NoneCoder1 小时前
CSS系列(36)-- Containment详解
前端·css
anyup_前端梦工厂1 小时前
初始 ShellJS:一个 Node.js 命令行工具集合
前端·javascript·node.js
5hand1 小时前
Element-ui的使用教程 基于HBuilder X
前端·javascript·vue.js·elementui
GDAL1 小时前
vue3入门教程:ref能否完全替代reactive?
前端·javascript·vue.js
六卿1 小时前
react防止页面崩溃
前端·react.js·前端框架
z千鑫2 小时前
【前端】详解前端三大主流框架:React、Vue与Angular的比较与选择
前端·vue.js·react.js
m0_748256142 小时前
前端 MYTED单篇TED词汇学习功能优化
前端·学习
小马哥编程3 小时前
Function.prototype和Object.prototype 的区别
javascript
小白学前端6663 小时前
React Router 深入指南:从入门到进阶
前端·react.js·react