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
Samplesnet45-mvcSenparc.Weixin.MP.Sample.sln
Senparc.Weixin.Sample项目下
Controllers/WxOpenController.cs
?
?
.NET Core 3.1
Samplesnetcore3.0-mvcSenparc.Weixin.Sample.NetCore3.vs2019.sln
学习 .NET Core 3.1
.NET 6.0(兼容5.0)
Samplesnet6-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',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)上面都有缺陷,导致无法正常解密,因此,建议直接升级到最新的版本(见上图)。升级基础库后,后端代码不需要修改。
?
下一篇我们将介绍微信公众号模板消息下线后,如何使用“订阅消息”进行开发。
(编辑:北几岛)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!