zoukankan      html  css  js  c++  java
  • [重要更新]微信小程序登录、用户信息相关接口调整:使用 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 官方微信开发视频教程:《微信公众号+小程序快速开发》
  • 相关阅读:
    HTML5结构
    HTML5新增的非主体元素header元素、footer元素、hgroup元素、adress元素
    CF GYM 100703G Game of numbers
    CF GYM 100703I Endeavor for perfection
    CF GYM 100703K Word order
    CF GYM 100703L Many questions
    CF GYM 100703M It's complicate
    HDU 5313 Bipartite Graph
    CF 560e Gerald and Giant Chess
    POJ 2479 Maximum sum
  • 原文地址:https://www.cnblogs.com/szw/p/14632314.html
Copyright © 2011-2022 走看看