微信JSSDK在IOS中invalid signature签名失败问题

2,886 阅读5分钟

业务场景

使用JSSDK开发微信公众号网页,支持在微信浏览器中、微信小程序中使用。微信小程序采用webview方式内嵌微信网页。
网页为React单页面应用,路由方式采用history。首页路由为/,登录页面为/login。

登录检测逻辑

进入首页/,检测当前页面登录状态,如已登录停留在首页/;如未登录则跳转登录页面/login。

代码版本1(错误):IOS网页、小程序报错

提供方

 cb.utils.initWeChat = function () {
     //传入url获取微信配置,包括签名等。
    const config = {
      url: "bill/client/pay/getWeChatConfig",
      method: "POST",
      params: {
        url:cb.rest.AppContext.serviceUrl + "/",
      },
    };
    proxy(config).then(function (json) {
      if (json.code !== 200) {
        console.error(json.message);
        return;
      }
      let obj = json.data;
      wx.config({
        debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        appId: obj.appId, // 必填,公众号的唯一标识
        timestamp: obj.timestamp, // 必填,生成签名的时间戳
        nonceStr: obj.nonceStr, // 必填,生成签名的随机串
        signature: obj.signature, // 必填,签名
        jsApiList: [
          "scanQRCode",
          "chooseImage",
          "getLocation",
          "getLocalImgData",
        ], // 必填,需要使用的JS接口列表
      });
      wx.ready(function () {
        console.log("wx初始化----ready");
      });
      wx.error(function (res) {
        console.log("wx初始化----error" + JSON.stringify(res));
      });
    });
  };

调用方

 cb.utils.initWeChat();

版本1代码问题

88c0b3e15f438cd89485709dc7cc333.jpg 安卓端网页无问题,在IOS端网页、小程序端的登录页面/login报错签名失败invalid signature。而登录后到首页/刷新网页则不会报签名失败错误。传递的url参数为/。 经过查阅资料了解到操作的浏览器历史记录,真实URL为第一次刚进入时的URL。理论上来说,传递的cb.rest.AppContext.serviceUrl + "/"即为首页,应不会报错。猜测url有字符不同。为了保险起见更改代码版本2,url参数改为初始化时从url取。

代码版本2(错误):IOS小程序报错

提供方

  //存储微信配置
 if (!window.__retail_wx_config) {
   window.__retail_wx_config = {
     iosHomePageUrl: null, //缓存ios第一次进入页面的url
   };
 }
 cb.utils.getIOSHomePage = function () {
   if (cb.utils.isIos()) {
     //ios需缓存第一次进入页面的url,否则在微信网页中wx.config鉴权失败invalid signature,在微信小程序webview未登录初始化会鉴权失败
     if(!window.__retail_wx_config.iosHomePageUrl){
       //只在第一次进入页面时候取
     window.__retail_wx_config.iosHomePageUrl = window.location.href
       .split("?")[0]
       .split("#")[0];
     }
     console.log(
       "当前为ios,ios首页url为",
       window.__retail_wx_config.iosHomePageUrl
     );
   }
 }
 cb.utils.initWeChat = function () {
    //传入url获取微信配置,包括签名等。
   const config = {
     url: "bill/client/pay/getWeChatConfig",
     method: "POST",
     params: {
       url: window.__retail_wx_config.iosHomePageUrl
           ? window.__retail_wx_config.iosHomePageUrl
           : cb.rest.AppContext.serviceUrl + "/",
     },
   };
   proxy(config).then(function (json) {
     ...
   });
 };

调用方

cb.utils.initWeChat();

版本2代码问题

IOS微信网页无问题了,但是在IOS微信小程序中登录后报错名失败invalid signature,realAuthUrl提示为登录页/login。
image.png
传递的url为/。理论上来说未登录跳转逻辑为/=>/login。已登录不跳转。则url应永远为/。由于报了这个错误,猜测webview里面IOS签名与url的获取/检测时机有区别。抱着试一试的态度更改为代码版本3,在小程序中使用setTimeout获取跳转后的url去签名,主要更改了调用时机。

代码版本3(正确)

提供方

  //存储微信配置
  if (!window.__retail_wx_config) {
    window.__retail_wx_config = {
      iosHomePageUrl: null, //缓存ios第一次进入页面的url
    };
  }
  cb.utils.getIOSHomePage = function () {
    if (cb.utils.isIos()) {
      //ios需缓存第一次进入页面的url,否则在微信网页中wx.config鉴权失败invalid signature,在微信小程序webview未登录初始化会鉴权失败,调用逻辑见src\mobile\containers\App\Index.jsx line31
      if(!window.__retail_wx_config.iosHomePageUrl){
        //只在第一次进入页面时候取
      window.__retail_wx_config.iosHomePageUrl = window.location.href
        .split("?")[0]
        .split("#")[0];
      }
      console.log(
        "当前为ios,ios首页url为",
        window.__retail_wx_config.iosHomePageUrl
      );
    }
  }
    cb.utils.initWeChat = function () {
    const config = {
      url: "bill/client/pay/getWeChatConfig",
      method: "POST",
      params: {
        url:
          window.__retail_wx_config.iosHomePageUrl
            ? window.__retail_wx_config.iosHomePageUrl
            : cb.rest.AppContext.serviceUrl + "/",
      },
    };
    proxy(config).then(function (json) {
      if (json.code !== 200) {
        // cb.utils.alert(json.message, 'error');
        console.error(json.message);
        return;
      }
      let obj = json.data;
      cb.rest.WeChatConfig = obj;
      wx.config({
        debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        appId: obj.appId, // 必填,公众号的唯一标识
        timestamp: obj.timestamp, // 必填,生成签名的时间戳
        nonceStr: obj.nonceStr, // 必填,生成签名的随机串
        signature: obj.signature, // 必填,签名
        jsApiList: [
          "scanQRCode",
          "chooseImage",
          "getLocation",
          "getLocalImgData",
        ], // 必填,需要使用的JS接口列表
      });
      wx.ready(function () {
        console.log("wx初始化----ready");
        cb.rest.weChatReady = true;
      });
      wx.error(function (res) {
        console.log("wx初始化----error" + JSON.stringify(res));
        cb.rest.weChatReady = false;
      });
    });
  };

调用方

此处初始化wxConfig,小程序环境与微信网页环境需区分,此处不要修改!!!,后续逻辑见src\mobile\init.jsx line 591,
      wx.miniProgram.getEnv((res) => {
        if (res.miniprogram) {
          setTimeout(function () {
            //重置ios首页变量start=============
            cb.utils.getIOSHomePage();
            //重置ios首页变量end=============
            cb.utils.initWeChat();
            console.log("小程序webview延迟执行initWeChat");
          });
        } else {
          cb.utils.getIOSHomePage();
          cb.utils.initWeChat();
          console.log("微信浏览器正常执行initWeChat");
        }
      });

总结

在微信环境中,单页面应用使用JSSDK初始化签名检测机制与当前页面的URL对比有兼容问题。主要表现为

  1. IOS与Andriod的页面真实URL不同,IOS为第一次刚进入时的URL。
  2. IOS在微信浏览器与在小程序webview中获取的真实URL不同,在小程序的webview中存储的真实URL应该是获取页面初始化之后(包含跳转)的URL(此项为测试后猜测)。 关于第一条IOS与Andriod的页面真实URL的相关资料还能查到,第二条微信浏览器和微信小程序webview的区别却没有找到相关资料,如有大佬找到相关资料,欢迎交流。 由于小程序的webview与JSSDK的ip白名单等问题,必须在线上测试。此问题耗费了3天时间,记录下,给后面遇到此问题的朋友做一点参考。

参考文章

微信JSSDK 签名错误invalid signature排查
调用wx.config时,遇到invalid signature的解决方法(解决IOS端签名失败问题)
微信JSSDK弹框显示config:invalid signature,realAuthURL