论微信静默授权以及踩坑点

微信静默授权流程

微信授权是指用户在微信客户端中访问第三方网页时,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现自己的业务逻辑。而静默授权则仅能获取到微信openId。

授权流程

授权登录以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)特点:用户无感知;
1.前端唤醒微信静默授权链接,该链接需与后端appId等信息一致。唤醒后,微信进行重定向到链接中拼接的redirectUrl地址,并在链接中拼接参数code
链接参考:
https://open.weixin.qq.com/connect/oauth2/authorize?appid="+wx_appid+"&redirect_uri="+api.wx_reg+"&response_type=code&scope=snsapi_base&state=1

2.前端获取到code后,将code传给后台,后台通过微信换取的code进行微信api授权获取用户openId,继而完成自己的下面的业务逻辑。相关代码操作可参考如下:

    private static final String GET_OPENID_CODE = "getOpenId:code:%s";
	
    @PostMapping(value = "getUserOpenId")
    public ResultData<RespUserVo> getUserOpenId(@RequestParam("code") String code) throws IOException {
        String key = String.format(GET_OPENID_CODE, reqWechatCodeDto.getCode());
        RespScopeInfoBo snsapiBaseResult = WeChatUtils.getSnsapiBaseResult(reqWechatCodeDto.getCode(), wechatInfo.getAppid(), wechatInfo.getSecret());
        if (StringUtils.isBlank(snsapiBaseResult.getOpenid())) {
            log.info("静默授权失败");
            return RespUtils.responseFail("静默授权失败!");
        }
        //没保存过用户需要保存
        String openid = snsapiBaseResult.getOpenid();
        log.info("静默授权成功openId:{}", openid);
        //后续的业务逻辑操作
        retutn Resputils.responseOk();
    }
public class WeChatUtils {
    /**
     * 获取静默授权Json
     */
    public static RespScopeInfoBo getSnsapiBaseResult(String code, String appid, String secret) throws IOException {
        if (StringUtils.isBlank(code)) {
            return null;
        }

        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code";
        String result = HttpUtil.get(url);
        log.info("微信静默授权返回的结果字符串:{}", result);
        RespScopeInfoBo respScopeInfoVo = JSONObject.parseObject(result, RespScopeInfoBo.class);
        return respScopeInfoVo;
    }
}

3.到这里就完成了静默授权的过程。

踩坑点

虽然完成了整个静默授权,但是踩坑点也从这里出来,开发用自己的微信测试的时候并没测出啥异常,但是业务上线后,收到了很多问题反馈,排查日志后,发现是openId获取不到,日志抛错为:

{“errcode”:40163,“errmsg”:“code been used, hints: [ req_id: hDLeY24ce-2ATWxa ]”}

{“errcode”:40029,“errmsg”:“invali code, hints: [ req_id: ceLeKRNre-ELzKhA ]”}

通过日志发现,报错的日志,传参进来的code是曾传参进来过的,微信文档上写着,code只能用一次,而且五分钟内有效,那么就可以理解为code是前端传重复的进来了,我们告知前端此事后,说他们可能存缓存里面了,导致重复code,锅此时甩给前端,但是前端小伙伴不认锅,说是微信给什么他们就传什么。双方僵持不下,给了日志他们看也不认锅。没办法,采取B方案。

B方案

获取code的逻辑不由前端去唤起,改由后端唤起,因为唤起逻辑本是一致,均是触发链接后,微信进行重定向回来,故B方案的流程为,前端触发后台接口,后台唤起授权链接,微信重定向回后台接口,此时携带参数code,后端获取到code再进行获取openId操作,但是这里不同的是,后端再将openId等参数可携带到url,或者写在cookie之类的返回给前端。也就是这里不同。相关代码参考如下,备注一点,这次重定向需要直接@Controller而不能使用@RestController

   /**
     * 前端触发userId
     *
     * @return
     */
    @GetMapping("getUserOpenId")
    public String getNewUserOpenId() throws Exception {
        log.info("进来获取Code");
        String url = this.getMpAuthorizeUrl("snsapi_base");
        return "redirect:" + url;
    }

 public String getMpAuthorizeUrl(String scope) throws Exception {
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize?";
        url += "appid=" + wechatInfo.getAppid();
        url += "&redirect_uri=" + java.net.URLEncoder.encode(hostConfig.getRedirectUrl(), "UTF-8");
        url += "&response_type=code";
        url += "&scope=" + scope;
        return url;
    }

再提供一个接口去接受微信返回的code

 @RequestMapping("/receiveCode")
    public String receiveCode(@RequestParam("code") String code) throws IOException {
        log.info("code:{}", code);
        if (StringUtils.isBlank(code)) {
            return "redirect:" + hostConfig.getUrl() + "?_=" + System.currentTimeMillis();
        }
        RespScopeInfoBo snsapiBaseResult = WeChatUtils.getSnsapiBaseResult(code, wechatInfo.getAppid(), wechatInfo.getSecret());

        if (StringUtils.isBlank(snsapiBaseResult.getOpenid())) {
            log.info("静默授权失败");
             return "redirect:" + hostConfig.getUrl() + "?_=" + System.currentTimeMillis();
        }
//todo 其他业务逻辑操作
        if (snsapiBaseResult != null) {
            RespUserVo userVo = RespUserVo.builder().id(user.getId()).wechatOpenid(openid).build();
          
            String url = hostConfig.getUrl() + "?userId=" + userVo.getId() + "&_=" + System.currentTimeMillis();
            log.info("最后重定向地址:{}", url);
            return "redirect:" + url;
        }
        return "redirect:" + hostConfig.getUrl() + "?_=" + System.currentTimeMillis();
    }

改造完毕后,上线,但是错误还是依旧会存在,通过打印的日志发现微信踩坑点确定,那就是微信的的确确会发送旧code给我!有人会说这个code可能会微信重定向之类的啊,不不不,通过日志发现,这个相同的code,返回的时间间隔有可能5分钟,12分钟,17分钟,最长的达到了五个小时,也就是五个小时后,返回来的code跟五个小时前的code是一样的,而第一次获取到的code是可以获取到openId,而后面的openId去获取的时候均报错,code被使用过或者违法的code错误。根据我们的B方案来看,我们的code是微信直接返回给我们后,我们去调用的,理应上是不能存在这个错误的,但是还是存在,那么我们无法改变微信,我们只能改变自己,那么就是加上缓存了。微信code进来后,我们将code缓存到redis,并将openId赋值为value,那么往后进来的重复code我们就不需要去调肯定会抛错的那个接口了。到这里,坑点解决。这里只记录微信存在这个bug。
注意:
有些人加上这个缓存后,可能会说还会抛错,那么麻烦看下这个code在以前的日志是否进来过。我们必须先缓存到第一个code,才不会报错,还会报错,有可能是因为进来过,缓存不到这个值,然后第二三次持续进来,就没办法了,但是用户端可以让他们重新刷新下,就可以解决这个问题。因为刷新后,进来的code不一样了

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
uni微信h5静默授权是指在用户进入uni微信H5页面时,通过微信授权接口获取用户的openid,并且不弹出授权页面让用户手动授权的一种授权方式。 实现uni微信H5静默授权获取openid的步骤如下: 1. 首先,在uni-app中引入微信JSSDK,通过在index.html中引入微信JS SDK库文件,或者通过npm安装并在main.js中引入微信JSSDK。 2. 在uni微信H5页面中编写获取openid的逻辑。可以在页面加载完成后,通过微信JSSDK提供的接口wx.config进行微信JS SDK的配置。在配置完成后,可以通过调用wx.ready函数,在ready回调函数中进行获取openid的操作。 3. 使用uni.request或uni.get请求后端接口,将微信提供的code发送至后端。 4. 后端接口需要通过微信网页授权接口,调用接口获取access_token和openid。接口调用成功后,可以把openid返回给前端。 5. 前端接收到openid后,可以进行后续的业务逻辑处理,例如用户登录、数据统计等。 需要注意的是,uni微信H5静默授权获取openid需要满足一定的条件,包括要求用户在微信客户端中已经授权过且未取消授权,页面的域名需要与微信公众平台的配置一致等。 总结起来,通过微信JSSDK的配置和调用微信网页授权接口,可以实现uni微信H5静默授权获取openid的功能。这使得开发者能够更加便捷地获取用户的openid,并基于openid实现个性化的功能和服务。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值