• [重要更新]微信小程序登录、用户信息相关接口调整:使用 wx.getUserProfile 取代 wx.getUserInfo


      2021年2月24日,微信官方团队发布了一个调整通知:《小程序登录、用户信息相关接口调整说明》,公告明确从4月13日起,所有发布的小程序将无法使用 wx.getUserInfo 接口(JS)和 <button open-type="getUserInfo"/> 标签来获取用户信息了。主要信息如下:

      

      

      实际时间从1个月前(4月2日)起,我们已经陆续接到开发者的反馈,在开发环境已经无法正常使用旧版本的功能,这也意味着从现在开始,要进行小程序的开发必须符合调整后接口的标准。

      虽然文档看上去很复杂,经过实际测试,其实修改的地方还是比较简单的,步骤如下:

      第一步:替换原有的 <button open-type="getUserInfo"/> 标签为普通标签,例如:  

    <button bindtap="getUserInfo"> 获取头像昵称 </button>

      在页面的 .js 文件中创建一个对应的方法 getUserInfo(如果以前就有可以直接修改): 

    getUserInfo: function (e) {
        //...  
    }

      第二步:在 getUserInfo 代码中调用 wx.getUserProfile 接口

    getUserProfile(e) {
        // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
        // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
        wx.getUserProfile({
          desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
          success: (res) => {
            this.setData({
              userInfo: res.userInfo,
              hasUserInfo: true
            })
          }
        })
      }

      完成。

       以下是新接口调用的效果:

          
     未登录状态  授权 完成授权 

     

       最新的 Demo 已经更新至 Senparc.Weixin SDK 的开源项目库:https://github.com/JeffreySu/WeiXinMPSDK

      小程序文件目录:srcSenparc.Weixin.WxOpensrcSenparc.Weixin.WxOpen.AppDemo

      后台程序目录如下:

    后台程序目录
    框架 解决方案  小程序 Controller 代码 学习新一代 .NET  
    .NET Framework 4.5

    Samples et45-mvcSenparc.Weixin.MP.Sample.sln

    Senparc.Weixin.Sample项目下

    Controllers/WxOpenController.cs

     
    .NET Core 3.1 Samples etcore3.0-mvcSenparc.Weixin.Sample.NetCore3.vs2019.sln 学习 .NET Core 3.1
    .NET 6.0(兼容5.0) Samples et6-mvcSenparc.Weixin.Sample.Net6.sln 学习 .NET 6.0

      在线 Demo:

    小程序二维码

      注意点

      1、建议将小程序基础库升级到最新,否则可能导致无法正确解密:

     

       2、注意 wx.getUserProfile 接口和 wx.login 接口的调用次序,Demo 中为了方便演示各项接口能力,所以进行了如下的嵌套操作:  

    wx.getUserProfile({
          desc: '用于完善会员资料',
          success: function (userInfoRes) {
            //...
            
            //调用 wx.login 登录接口
            wx.login({
            success: function (res) {
              //换取openid & session_key
              wx.request({
                url: wx.getStorageSync('domainName') + '/WxOpen/OnLogin',
                method: 'POST',
                header: { 'content-type': 'application/x-www-form-urlencoded' },
                data: {
                  code: res.code
                },
                success:function(json){
                  var result = json.data;
                  if(result.success)
                  {
                    wx.setStorageSync('sessionId', result.sessionId);
                    //校验
                    wx.request({
                      url: wx.getStorageSync('domainName') + '/WxOpen/CheckWxOpenSignature',
                      method: 'POST',
                      header: { 'content-type': 'application/x-www-form-urlencoded' },
                      data: {
                        sessionId: result.sessionId,//wx.getStorageSync('sessionId'),
                        rawData:userInfoRes.rawData,
                        signature:userInfoRes.signature
                      },
                      success:function(json){
                        console.log(json.data);
                      }
                    });
    
                    //解密数据(建议放到校验success回调函数中,此处仅为演示)
                    wx.request({
                      url: wx.getStorageSync('domainName') + '/WxOpen/DecodeEncryptedData',
                      method: 'POST',
                      header: { 'content-type': 'application/x-www-form-urlencoded' },
                      data: {
                        'type':"userInfo",
                        sessionId: result.sessionId,//wx.getStorageSync('sessionId'),
                        encryptedData: userInfoRes.encryptedData,
                        iv: userInfoRes.iv
                      },
                      success:function(json){
                        console.log('数据解密:', json.data);
                      }
                    });
                    
                  }else{
                    console.log('储存session失败!',json);
                  }
                }
              })
            }
          })
        }
    });    
    

      相关后端代码,如果是新项目,只需要参考 Demo 提供的代码即可,旧项目不需要修改:

      wx.login 成功后,调用 WxOpenController.cs 中的 OnLogin 方法:

     1       /// <summary>
     2         /// wx.login登陆成功之后发送的请求
     3         /// </summary>
     4         /// <param name="code"></param>
     5         /// <returns></returns>
     6         [HttpPost]
     7         public ActionResult OnLogin(string code)
     8         {
     9             try
    10             {
    11                 var jsonResult = SnsApi.JsCode2Json(WxOpenAppId, WxOpenAppSecret, code);
    12                 if (jsonResult.errcode == ReturnCode.请求成功)
    13                 {
    14                     //Session["WxOpenUser"] = jsonResult;//使用Session保存登陆信息(不推荐)
    15                     //使用SessionContainer管理登录信息(推荐)
    16                     var unionId = "";
    17                     var sessionBag = SessionContainer.UpdateSession(null, jsonResult.openid, jsonResult.session_key, unionId);
    18 
    19                     //注意:生产环境下SessionKey属于敏感信息,不能进行传输!
    20                     return Json(new { success = true, msg = "OK", sessionId = sessionBag.Key, sessionKey = sessionBag.SessionKey });
    21                 }
    22                 else
    23                 {
    24                     return Json(new { success = false, msg = jsonResult.errmsg });
    25                 }
    26             }
    27             catch (Exception ex)
    28             {
    29                 return Json(new { success = false, msg = ex.Message });
    30             }
    31         }

       OnLogin 方法调用成功后进行签名校验:

     1         /// <summary>
     2         /// 检查签名
     3         /// </summary>
     4         /// <param name="sessionId"></param>
     5         /// <param name="rawData"></param>
     6         /// <param name="signature"></param>
     7         /// <returns></returns>
     8         [HttpPost]
     9         public ActionResult CheckWxOpenSignature(string sessionId, string rawData, string signature)
    10         {
    11             try
    12             {
    13                 var checkSuccess = Senparc.Weixin.WxOpen.Helpers.EncryptHelper.CheckSignature(sessionId, rawData, signature);
    14                 return Json(new { success = checkSuccess, msg = checkSuccess ? "签名校验成功" : "签名校验失败" });
    15             }
    16             catch (Exception ex)
    17             {
    18                 return Json(new { success = false, msg = ex.Message });
    19             }
    20         }

       同时进行用户信息解密及水印校验:

     1         /// <summary>
     2         /// 数据解密并进行水印校验
     3         /// </summary>
     4         /// <param name="type"></param>
     5         /// <param name="sessionId"></param>
     6         /// <param name="encryptedData"></param>
     7         /// <param name="iv"></param>
     8         /// <returns></returns>
     9         [HttpPost]
    10         public async Task<IActionResult> DecodeEncryptedData(string type, string sessionId, string encryptedData, string iv)
    11         {
    12             DecodeEntityBase decodedEntity = null;
    13 
    14             try
    15             {
    16                 switch (type.ToUpper())
    17                 {
    18                     case "USERINFO"://wx.getUserInfo()
    19                         decodedEntity = EncryptHelper.DecodeUserInfoBySessionId(
    20                             sessionId,
    21                             encryptedData, iv);
    22                         break;
    23                     default:
    24                         break;
    25                 }
    26             }
    27             catch (Exception ex)
    28             {
    29                 WeixinTrace.SendCustomLog("EncryptHelper.DecodeUserInfoBySessionId 方法出错",
    30                     $@"sessionId: {sessionId}
    31 encryptedData: {encryptedData}
    32 iv: {iv}
    33 sessionKey: { (await SessionContainer.CheckRegisteredAsync(sessionId)
    34                 ? (await SessionContainer.GetSessionAsync(sessionId)).SessionKey
    35                 : "未保存sessionId")}
    36 
    37 异常信息:
    38 {ex.ToString()}
    39 ");
    40             }
    41 
    42             //检验水印
    43             var checkWatermark = false;
    44             if (decodedEntity != null)
    45             {
    46                 checkWatermark = decodedEntity.CheckWatermark(WxOpenAppId);
    47 
    48                 //保存用户信息(可选)
    49                 if (checkWatermark && decodedEntity is DecodedUserInfo decodedUserInfo)
    50                 {
    51                     var sessionBag = await SessionContainer.GetSessionAsync(sessionId);
    52                     if (sessionBag != null)
    53                     {
    54                         await SessionContainer.AddDecodedUserInfoAsync(sessionBag, decodedUserInfo);
    55                     }
    56                 }
    57             }
    58 
    59             //注意:此处仅为演示,敏感信息请勿传递到客户端!
    60             return Json(new
    61             {
    62                 success = checkWatermark,
    63                 //decodedEntity = decodedEntity,
    64                 msg = $"水印验证:{(checkWatermark ? "通过" : "不通过")}"
    65             });
    66         }

       上述方法中标红的接口调用、SessionKey管理和解密方法都已经封装在 Senparc.Weixin SDK 中(更多教程),只需要按照 Demo 演示的调用即可。

      调试窗口结果:

      

       注意:

      1、不能在调用 wx.login 等过程的回调函数中,自动调用 wx.getUserProfile 来触发授权行为,因为 wx.getUserProfile 只能由用户手动触发。否则,系统会抛出异常:

     error msg: getUserProfile:fail can only be invoked by user TAP gesture

       关于这两个方法的同时使用问题也可以参考:《wx.getUserProfile不能和wx.login一起使用?》(PS:并非所有都是正解)

      2、虽然官方提示需要使用2.10.4以上基础库,但是实测发现,2.10.4及之后的几个版本,虽然可以使用wx.getUserProfile,但在用户信息解密(wx.login)上面都有缺陷,导致无法正常解密,因此,建议直接升级到最新的版本(见上图)。升级基础库后,后端代码不需要修改。

      下一篇我们将介绍微信公众号模板消息下线后,如何使用“订阅消息”进行开发。

    转载请注明出处和作者,谢谢!
    作者:JeffreySu / QQ:498977166
    博客:http://szw.cnblogs.com/

    Senparc官方教程《微信开发深度解析:微信公众号、小程序高效开发秘籍》,耗时2年精心打造的微信开发权威教程,点击这里,购买正版
    
微信开发深度解析:微信公众号、小程序高效开发秘籍

    Senparc 官方微信开发视频教程:《微信公众号+小程序快速开发》,点击这里点击观看
    Senparc 官方微信开发视频教程:《微信公众号+小程序快速开发》
  • 相关阅读:
    文字列をバイトで切る
    把SmartForm转换成PDF
    相对布局和网格布局
    帧布局和表格布局
    计算器布局
    课堂总结和练习
    Android UI组件
    2层导航
    导航
    课堂总结
  • 原文地址:https://www.cnblogs.com/szw/p/14632314.html
Copyright © 2020-2023  润新知