[重要更新]微信小程序登录、用户信息相关接口调整:使用 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

  小程序文件目录:\src\Senparc.Weixin.WxOpen\src\Senparc.Weixin.WxOpen.AppDemo

  后台程序目录如下:

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

\Samples\net45-mvc\Senparc.Weixin.MP.Sample.sln

Senparc.Weixin.Sample项目下

Controllers/WxOpenController.cs

 

 

.NET Core 3.1 \Samples\netcore3.0-mvc\Senparc.Weixin.Sample.NetCore3.vs2019.sln 学习 .NET Core 3.1
.NET 6.0(兼容5.0) \Samples\net6-mvc\Senparc.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',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',data: {
                    'type':"userInfo",sessionId: result.sessionId,encryptedData: userInfoRes.encryptedData,iv: userInfoRes.iv
                  },success:function(json){
                    console.log('数据解密:',json.data);
                  }
                });
                
              }else{
                console.log('储存session失败!',json);
              }
            }
          })
        }
      })
    }
});    

 

  相关后端代码,如果是新项目,只需要按照之前的实现方式,旧项目不需要修改:

  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                     false,msg = jsonResult.errmsg });
25 26             }
27             catch (Exception ex)
28 29                  ex.Message });
30 31         }

 

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

 1          检查签名
<param name="sessionId"></param>
<param name="rawData"></param>
 6         <param name="signature"></param>
 7          9         public ActionResult CheckWxOpenSignature(string sessionId,1)">string rawData,1)"> signature)
11             12 13                 var checkSuccess = Senparc.Weixin.WxOpen.Helpers.EncryptHelper.CheckSignature(sessionId,rawData,signature);
14                 new { success = checkSuccess,msg = checkSuccess ? 签名校验成功" : 签名校验失败" });
15 16             17 18                 19 20         }

 

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

 数据解密并进行水印校验
<param name="type"></param>
<param name="encryptedData"></param>
<param name="iv"></param>
 8          9 10         public async Task<IActionResult> DecodeEncryptedData(string type,1)">string encryptedData,1)"> iv)
11 12             DecodeEntityBase decodedEntity = 13 
14             16                 switch (type.ToUpper())
18                     case USERINFO":wx.getUserInfo()
19                         decodedEntity = EncryptHelper.DecodeUserInfoBySessionId(
20                             sessionId,                            encryptedData,iv);
22                         break23                     default:
24                         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 = false44             if (decodedEntity != )
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 != 53                     {
54                          SessionContainer.AddDecodedUserInfoAsync(sessionBag,decodedUserInfo);
55                     }
56 57 58 
59             注意:此处仅为演示,敏感信息请勿传递到客户端!
60             new
61 62                 success = checkWatermark,1)">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)上面都有缺陷,导致无法正常解密,因此,建议直接升级到最新的版本(见上图)。升级基础库后,后端代码不需要修改。

 

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

原文地址:https://www.cnblogs.com/szw

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


在上文中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发、订阅和处理的流程。这种实现太简单了,百十行代码就展示了一个基本工作原理。然而,要将这样的解决方案运用到实际生产环境,还有很长的路要走。今天,我们就研究一下在事件处理器中,对象生命周期的管理问题。事实上,不仅仅是在事件处理器
上文已经介绍了Identity Service的实现过程。今天我们继续,实现一个简单的Weather API和一个基于Ocelot的API网关。 回顾 《Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(一)》 Weather API Weather
最近我为我自己的应用开发框架Apworks设计了一套案例应用程序,并以Apache 2.0开源,开源地址是:https://github.com/daxnet/apworks-examples,目的是为了让大家更为方便地学习和使用.NET Core、最新的前端开发框架Angular,以及Apwork
HAL(Hypertext Application Language,超文本应用语言)是一种RESTful API的数据格式风格,为RESTful API的设计提供了接口规范,同时也降低了客户端与服务端接口的耦合度。很多当今流行的RESTful API开发框架,包括Spring REST,也都默认支
在前面两篇文章中,我详细介绍了基本事件系统的实现,包括事件派发和订阅、通过事件处理器执行上下文来解决对象生命周期问题,以及一个基于RabbitMQ的事件总线的实现。接下来对于事件驱动型架构的讨论,就需要结合一个实际的架构案例来进行分析。在领域驱动设计的讨论范畴,CQRS架构本身就是事件驱动的,因此,
HAL,全称为Hypertext Application Language,它是一种简单的数据格式,它能以一种简单、统一的形式,在API中引入超链接特性,使得API的可发现性(discoverable)更强,并具有自描述的特点。使用了HAL的API会更容易地被第三方开源库所调用,并且使用起来也很方便
何时使用领域驱动设计?其实当你的应用程序架构设计是面向业务的时候,你已经开始使用领域驱动设计了。领域驱动设计既不是架构风格(Architecture Style),也不是架构模式(Architecture Pattern),它也不是一种软件开发方法论,所以,是否应该使用领域驱动设计,以及什么时候使用
《在ASP.NET Core中使用Apworks快速开发数据服务》一文中,我介绍了如何使用Apworks框架的数据服务来快速构建用于查询和管理数据模型的RESTful API,通过该文的介绍,你会看到,使用Apworks框架开发数据服务是何等简单快捷,提供的功能也非常多,比如对Hypermedia的
在上一讲中,我们已经完成了一个完整的案例,在这个案例中,我们可以通过Angular单页面应用(SPA)进行登录,然后通过后端的Ocelot API网关整合IdentityServer4完成身份认证。在本讲中,我们会讨论在当前这种架构的应用程序中,如何完成用户授权。 回顾 《Angular SPA基于
Keycloak是一个功能强大的开源身份和访问管理系统,提供了一整套解决方案,包括用户认证、单点登录(SSO)、身份联合、用户注册、用户管理、角色映射、多因素认证和访问控制等。它广泛应用于企业和云服务,可以简化和统一不同应用程序和服务的安全管理,支持自托管或云部署,适用于需要安全、灵活且易于扩展的用
3月7日,微软发布了Visual Studio 2017 RTM,与之一起发布的还有.NET Core Runtime 1.1.0以及.NET Core SDK 1.0.0,尽管这些并不是最新版,但也已经从preview版本升级到了正式版。所以,在安装Visual Studio 2017时如果启用了
在上文中,我介绍了如何在Ocelot中使用自定义的中间件来修改下游服务的response body。今天,我们再扩展一下设计,让我们自己设计的中间件变得更为通用,使其能够应用在不同的Route上。比如,我们可以设计一个通用的替换response body的中间件,然后将其应用在多个Route上。 O
不少关注我博客的朋友都知道我在2009年左右开发过一个名为Apworks的企业级应用程序开发框架,旨在为分布式企业系统软件开发提供面向领域驱动(DDD)的框架级别的解决方案,并对多种系统架构风格提供支持。这个框架的开发和维护我坚持了很久,一直到2015年,我都一直在不停地重构这个项目。目前这个项目在
好吧,这个题目我也想了很久,不知道如何用最简单的几个字来概括这篇文章,原本打算取名《Angular单页面应用基于Ocelot API网关与IdentityServer4ʺSP.NET Identity实现身份认证与授权》,然而如你所见,这样的名字实在是太长了。所以,我不得不缩写“单页面应用”几个字
在前面两篇文章中,我介绍了基于IdentityServer4的一个Identity Service的实现,并且实现了一个Weather API和基于Ocelot的API网关,然后实现了通过Ocelot API网关整合Identity Service做身份认证的API请求。今天,我们进入前端开发,设计
Ocelot是ASP.NET Core下的API网关的一种实现,在微服务架构领域发挥了非常重要的作用。本文不会从整个微服务架构的角度来介绍Ocelot,而是介绍一下最近在学习过程中遇到的一个问题,以及如何使用中间件(Middleware)来解决这样的问题。 问题描述 在上文中,我介绍了一种在Angu
在大数据处理和人工智能时代,数据工厂(Data Factory)无疑是一个非常重要的大数据处理平台。市面上也有成熟的相关产品,比如Azure Data Factory,不仅功能强大,而且依托微软的云计算平台Azure,为大数据处理提供了强大的计算能力,让大数据处理变得更为稳定高效。由于工作中我的项目
在上文中,我们讨论了事件处理器中对象生命周期的问题,在进入新的讨论之前,首先让我们总结一下,我们已经实现了哪些内容。下面的类图描述了我们已经实现的组件及其之间的关系,貌似系统已经变得越来越复杂了。其中绿色的部分就是上文中新实现的部分,包括一个简单的Event Store,一个事件处理器执行上下文的接
在之前《在ASP.NET Core中使用Apworks快速开发数据服务》一文的评论部分,.NET大神张善友为我提了个建议,可以使用Compile As a Service的Roslyn为语法解析提供支持。在此非常感激友哥给我的建议,也让我了解了一些Roslyn的知识。使用Roslyn的一个很大的好处
很长一段时间以来,我都在思考如何在ASP.NET Core的框架下,实现一套完整的事件驱动型架构。这个问题看上去有点大,其实主要目标是为了实现一个基于ASP.NET Core的微服务,它能够非常简单地订阅来自于某个渠道的事件消息,并对接收到的消息进行处理,于此同时,它还能够向该渠道发送事件消息,以便