weixin公众号页面返回上一层_偶买嘎,看耀哥带你如何实现公众号网页授权

前言

嗨喽,各位小伙伴,美好的一天从耀哥开始~ 今天给大家分享微信公众号H5开发中的网页授权。

「微信官方文档·公众号_网页授权」 >> https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html

开始之前,我们先了解几个概念:

「OpenID & UnionID」

OpenID 和 UnionID 为用户的唯一标识。其中:

  • OpenID:表示微信用户对于某个 特定 小程序或者公众号的唯一标识,开发者可以通过这个标识识别用户。

  • UnionID:表示微信用户对于 同一商户主体 下的微信小程序或者公众号的唯一标识。开发者需要在微信开放平台绑定相同账号的主体。通过 UnionID,可实现多个小程序、公众号、甚至APP之间的数据互通。

可能有的小伙伴比较费解,既然已经有了标识用户的 OpenID,为什么还需要 UnionID 呢?据官网介绍,如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的UnionID来区分用户的唯一性,因为同一用户,对同一个微信开放平台下的不同应用(移动应用、网站应用和公众帐号),UnionID是相同的。为了帮助大家理解,我给大家举个例子:

比如我有A/B/C三个公众号商城,小明进入商城后会产出3个不同的OpenID:

公众号唯一标识
AOpenID__A
BOpenID__B
COpenID__C

那岂不是有3个小明用户?简单想像一下,你从公众号里进入一个网页版的拼夕夕商城,账号里有10个拼豆,但是进入小程序版的拼夕夕商城,账号里却只有1个拼豆,是不是很茫然?为了防止这样的“怪异”现象发生,我们要解决的问题是:要如何确定小明这个人在进入“同一个”商城中,是“同一个”用户呢?那就是使用 UnionID 啦。

「应用授权作用域」

网页授权scope分两种:

  • snsapi_base:不弹出授权页面,直接跳转,即静默授权,但只能获取用户OpenID。
  • snsapi_userinfo:弹出授权页面,获取用户基本信息,需用户手动同意授权,一旦同意授权,即可在不关注公众号的情况下获取用户信息。

提示:

  1. 对于已关注公众号的用户,如果用户从公众号的会话或者自定义菜单进入本公众号的网页授权页,即使是scope为snsapi_userinfo,也是静默授权,用户无感知。
  2. 用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注事件推送后,才能根据用户OpenID来获取用户基本信息。这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。

「相关域名介绍」

  • 业务域名:项目部署域名,如果不设置,微信会提示不安全,“For security,never share your password.”
  • JS接口安全域名:调用JS-SDK时配置;
  • 网页授权域名:获取用户唯一标识(OpenID)或用户信息时配置;

准备

  1. 首先注册公众号,然后在公众号后台 “「开发 - 基本配置」 ” 中获取 appIDappsecret

  2. 接下来你需要在公众后台 “「设置 - 公众号设置 - 功能设置」” 中完善 业务域名JS接口安全域名网页授权域名 配置项。

5501c40e128aaa3dfa1d51cf6cf2a3d3.png

提示:

  1. 如果项目中没有用到JS-SDK,则 JS接口安全域名 可不配置。
  2. 由于业务域名JS接口安全域名网页授权域名 配置项在设置时有修改次数及配置域名个数限制。所以在开发阶段我们可以使用测试号(测试号领取链接:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login)开发,但需要注意的是,测试号无法获取用户的 UnionID 以及拉起微信支付弹框等操作。

思路

网页授权流程大致分为四步:

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

第二步:通过code换取网页授权access_token(后端实现)

第三步:刷新access_token(如果需要)(后端实现)

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

其中,第二步到第四步由后端实现,所以前端只需要拿到用户授权code之后发送给后端即可。

提示:code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

实际开发中,我们需结合实际场景处理网页授权。所以,思路应该是这样的:在公众号H5入口页判断本地是否存在token,如果存在则校验token是否过期,倘若token不存在,或者token已过期则直接跳转至授权页,再执行登陆操作。否则直接跳转至主页。一般来说,如果token存在我们也可以不用去校验token是否过期,因为当我们拿着过期的token去请求数据时,后端会返回表示token过期的状态码,此时我们可以在ajax请求拦截中做处理。

实现

这里主要以伪代码实现,仅供大家参考,首先专门定义一个路由 /auth/:type 处理授权,由于网页授权还需一个回调页,为了便于集中处理,我一般是将授权和回调逻辑写在一个路由中的,即:

/auth/jump:授权跳转页;

/auth/callback:授权回调页;

接下来,我们一起看看具体实现方式。

「1. 校验是否授权」

为了不让用户每次访问公众号页面时就去拉一次授权,所以我们需在项目入口文件中判断本地是否存在用户上一次授权登陆之后保存下来的token,如果存在,还得判断token是否过期,当token不存在或者已过期时,我们才会去拉授权,伪代码如下:

// 判断本地是否存在token
if(localStorage.getItem('token')) {
  // 存在:判断token是否过期
  const isExpire = checkToken();
  if(isExpire) {
    // token已过期:跳转授权页
    history.replace('/auth/jump');
  }else {
    // token未过期:跳转至首页
    history.replace('/index');
  }
} else {
  // 不存在:跳转授权页
  history.replace('/auth/jump');
}

「2. 处理授权」

由于我习惯性将授权和回调写在一个文件里,所以我们可以根据path参数判断是处理授权还是处理回调。

我们先来看看如何处理跳转微信授权页:

 const handleJump = () => {
    // 授权后重定向的回调链接地址
    const redirect_uri = encodeURIComponent(`${window.location.origin}/auth/callback`);
    const appId = 'wx169565989539bf7d';
    // 重定向后会带上state参数
    const state = 'Muzili';
    // 拼接微信授权地址
    const url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_userinfo&state=${state}#wechat_redirect`;
    // 跳转至微信授权页
    window.location.replace(url);
  }

如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE (携带code及state参数),接下来我们处理回调:

 const handleCallback = () => {
    // 解析query参数
    const { code, state } = Tools.query();
    // 调用登录接口,将code交由后台解析用户信息
    Api.user.login({
        code
    }).then(res => {
        // 存储token
        localStorage.setItem('token', res.token);
        // 跳转至首页
        history.replace('/index');
    })
  }

*上述代码中的 Tools 为耀哥封装的工具类 lg-tools,已发布至npm。

以上代码仅供参考,给大家一个实现思路,大家可据此一试。

扩展

「1. 授权登陆之后,由于长时间没有操作,token过期了怎么办?」

这种情况是比较普遍的,为了安全考虑,后端一般会给token设置有效期,如果你在有效期内请求了接口,后端会自动续期(根据后端策略),那如果用户长时没有操作,token就会失效,此时用户再次发起请求时后端就会返回token过期的信息,显然得重新拉一次授权进行登录。当页面和请求较多时,这个问题可以在请求响应拦截器里面处理,通常后端会返回一个状态码,比如token过期的状态码是 -10,当你判断后端返回的状态码为 -10 时直接跳转至 /auth 授权页就行了,这一系列操作想必各位已经比较熟悉了。但是目前存在的问题是,假设我当前在/details 页面中,当我跳转至 /auth 授权页授权登陆之后,我又如何回到 /details 路由呢?这个问题其实特别容易解决,我们只需在拦截器里跳转至授权页时将当前页的路由作为参数传递给 /auth/jump 页,如下所示:

// 响应拦截
service.interceptors.response.use(async (response, options) => {
  const res = await response.clone().json();
  // 为了避免在一个页面中同时发起多次请求跳转多次授权页
  // 所以判断:如果当前已经在授权页才接收到另一次请求的过期状态则不作处理
  if(res.code === -10 && !/auth/.test(location.href)) {
    // token 过期/重新授权
    history.replace(`/auth/jump?from=${encodeURIComponent(location.href.replace(location.origin, ''))}`)
  }
  return res;
});

然后再将其作为 state 值一并发送给微信授权即可:

 const handleJump = () => {
    const redirect_uri = encodeURIComponent(`${window.location.origin}/auth/callback`);
    const appId = 'wx169565989539bf7d';
    // 获取跳转链接/如果不存在则默认跳转至首页
    const state = Tools.query('from') || '/index';
    const url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_userinfo&state=${state}#wechat_redirect`;
    window.location.replace(url);
  }

当授权回调时,会将code和state作为query参数一并返回,所以你只需要在授权回调页拿到state作为跳转路由即可。

 const handleCallback = () => {
    const { code, state } = Tools.query();
    Api.user.login({
        code
    }).then(res => {
        localStorage.setItem('token', res.token);
        // 跳转至指定路由
        history.replace(state);
    })
  }

尾言

好啦,各位小伙伴,今天的分享就到这里啦,是不是很简单呢?赶快去试试吧。如果您喜欢耀哥的分享,还请点一波关注,您的关注与支持,是我唯一写作下去的动力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值