微信小程序如何获取用户信息

news2024/12/25 2:43:13

自我介绍

我是IT果果日记,微信公众号请搜索 IT果果日记
一个普通的技术宅,定期分享技术文章,欢迎点赞、关注和转发,请多关照。
  • 微信小程序用户基本信息有哪些?

  • 除了基本信息,微信还会提供openId和unionId,它们有什么作用和区别?

  • 在获取用户信息的过程中,如何知道明文数据是否被篡改了?

  • session_key 该如何使用呢?

带着这些问题,我们开始今天的学习。

获取用户基本信息

小程序提供了一个 wx.getUserProfile(OBJECT) 方法来获取用户的信息。以前的老版本是用的 wx.getUserProfile(OBJECT) 方法,现在以及被官方不推荐使用了。

用户信息分为用户基本信息和用户openId、UnionId。基本信息是明文的,而openId和UnionId是加密数据。这两种类型的数据都由wx.getUserProfile(OBJECT)方法返回。

用户基本信息包括以下7项:

  • avatarUrl 用户微信头像的URL地址。

  • city 城市。

  • country 国家。

  • gender 性别,1表示男,2表示女,0表示未知。

  • language 语言区域。

  • nickName 昵称。

  • province:省份。

在小程序中,用户的基本信息可以轻易获得,他们是明文的、不加密的。但 openId UnionId 是加密的。什么是openId和UnionId呢?可以将openId和UnionId理解为用户在微信应用中的id号。

他们的区别是:

  • openId只代表用户在某个微信应用下的id号;

  • 而UnionId是跨应用的,同一用户在同一开发者的多个应用里,UnionId是唯一的。

官方文档对于UnionId的描述非常清楚:如果开发者拥有多个移动应用、网站应用和公众账号(包括小程序),可通过UnionId区分用户的唯一性,因为只要是同一个微信开放平台账号下的移动应用、网站应用和公众账号(包括小程序),用户的UnionId就是唯一的。换句话说,同一用户在同一个微信开放平台下的不同应用中,UnionId是相同的。

所以,openId不能跨应用,如果要在多应用间统一用户身份,请使用UnionId。这里要注意,在小程序中使用UnionId首先需要前往微信开放平台绑定小程序。请参考官方文档:

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html

微信开放平台绑定小程序流程

登录微信开放平台 — 管理中心 — 小程序 — 绑定小程序

微信开放平台绑定小程序

下面来看wx.getUserProfile(OBJECT)方法的使用。wx.getUserProfile的OBJECT参数有3个回调函数:success、fail和complete。在这3个回调函数中,重点介绍success。success方法的返回值有以下5个:

  • userInfo 用户基本信息对象,不包含openId等敏感信息。

  • rawData 不包含敏感信息的基本信息字符串,通常用来计算签名,防止从微信返回的用户信息被篡改。

  • signature 使用sha1(rawData+sessionkey)得到字符串,用于校验用户信息。

  • encryptedData 包括敏感数据在内的完整用户信息的加密数据。

  • iv 加密算法的初始向量。

现在,我们在代码中获取用户的明文信息。代码如下:

_getUserInfo: function() {
	var userInfoStorage= wx.getStorageSync(user);
	if (!userInfoStorage) {
		//如果缓存中没有用户信息,那么获取用户信息
		var that = this;
		wx.login({
			success: function (){
				wx.getUserProfile({
					success: function (res){
						that.globalData.userInfo = res.userInfo
						//将用户的基本信息保存到缓存中
						wx.setStorageSync('user',res.userInfo)
					},
					fail: function (res){
						console.log(res);
					}
				})
			}
		})
	}
	else {
		//如果缓存中已经存在用户的基本信息,那么将信息保存到全局变量中
		this.globalData.userInfo = userInfoStorage;
	}
}

解释一下上述代码。为了避免每次启动小程序时都要在微信服务器中加载用户的基本信息,我们将用户信息保存到缓存中。这样,每次启动小程序时先去看看缓存有没有数据,如果没有,就调用wx.getUserProfile获取用户信息并保存到缓存和全局变量userInfo中;如果有,就直接将用户信息保存到全局变量userInfo里。

细心的朋友可能注意到,我们并不是直接调用wx.getUserProfile(OBJECT)方法,而是先调用wx.login,在wx.login调用成功后再继续调用wx.getUserProfile。之所以在wx.login调用成功后才调用wx.getUserProfile,是因为官方文档明确指出了获取用户信息需要先调用wx.login。同时,在官方的示例项目中也是先调用wx.login。至于wx.login有什么作用,请耐心的往下看,大家只需“依葫芦画瓢”,照做即可。

事实上,如果你只想获取用户的明文基本信息,那么不调用wx.login,直接调用wx.getUserProfile也可以获取用户信息。所以,是否在调用wx.getUserProfile前调用wx.login请大家自行决定。

当第一次运行以上代码并调用wx.getUserProfile时,小程序会弹出如图所示的提示窗口,让用户选择是否授权获取用户的基本信息。

用户授权获取信息

用户点击“允许”后,才会执行wx.getUserProfile的success回调函数,如果点击“拒绝”,将执行fail回调函数。

有些开发者在测试时可能永远不会弹出这个授权窗口。因为如果当前项目没有appId,那么用户信息是由微信模拟的信息,并没有进行真实的获取用户信息流程,所以不会出现这个窗口,且开发工具会有一个警告提示,如图所示。

没有appId时是开发工具模拟的用户数据

当然,这个用户数据也是真实的用户数据,因为你在使用开发工具时必须扫描二维码登录,这样开发工具就能知道你的微信身份,自然可以模拟返回你的用户数据。但模拟数据相比于真实的用户数据缺少3个属性,即signature、encryptedData和iv。也就是说,模拟数据只有明文信息而没有加密信息。

将用户信息保存到缓存中有一个缺点,就是没办法实时更新用户信息(比如用户更改了自己的微信资料),但这是具体业务的问题,需要开发者在实际项目编写中灵活处理。

用户信息校验

上文已经介绍了如何调用微信登录接口以及获取用户信息。另外,在我以往的文章中也介绍了如何通过登录接口返回的code获取到session_key。之前提了一个问题,session_key是做什么用的呢?下面就讲解一下session_key的作用以及它的用法。

先来看看wx.getUserProfile返回的数据:

  • userInfo 用户基本信息对象,不包含openId等敏感信息。

  • rawData 不包含敏感信息的基本信息字符串,通常用来计算签名,防止从微信返回的用户信息被篡改。

  • signature 使用sha1(rawData+sessionkey)得到字符串,用于校验用户信息。

  • encryptedData 包括敏感数据在内的完整用户信息的加密数据。

  • iv 加密算法的初始向量。

我们使用了userInfo对象,包括userInfo和rawData在内的明文数据都可能存在被篡改的风险。如何知道明文数据是否被篡改了呢?

这个时候rawData和singature就可以发挥作用了。rawData和signature用于校验用户数据到底有没有被篡改过(没有绝对安全的网络,数据极有可能被抓包或者通过其他方式篡改)。通常来说,想要实现这个校验必须在服务器编码才能进行。这需要小程序将获取的rawData和signature一并提交到服务器,由服务器完成校验工作。

校验的基本原理是:rawData是用户原始明文数据,signature是使用sha1(rawData+sessionkey)得到的字符串。理论上讲,如果数据没有被篡改,那么signature等于sha1(rawData+sessionkey);如果rawData或者signature被修改了,那么signature必然不再等于sha1(rawData+sessionkey)。

是否存在signature和rawData同时被修改的情况呢?理论上是不可能的,因为session_key并不在网络上传输,篡改者不知道这个变量,被篡改且校验通过的概率很小。

有可能从signature中推算出session_key吗?理论上讲,这是不可能的。因为sha1算法是不可逆的,无法在已知rawData和signature的情况下推算出session_key。不知道session_key就无法通过同时修改rawData和signature达到“欺骗校验的目的”。如果知道了session_key,只需要修改rawData并重新用session_key计算一下新的sha1(rawData+session_key)就又可以让新的rawData等于新的sha1(rawData+session_key)了。这样,开发者就无法知道rawData是被修改过的。

这也是为什么官方文档一再强调,不要在网络上传输session_key,而应该将其保存在服务器上使用,以降低session_key被泄露的风险。

session_key有点类似于我们在数据库中保存用户密码时所使用的“盐(salt)”。在数据库保存用户密码时,并不是直接将用户的密码以明文的方式存放在数据库表中,通常都会使用SHA-1或者MD5算法将用户密码和salt随机字符串拼接在一起,重新计算一下再存入数据库中。被重新使用SHA-1或MD5算法计算的用户密码谁都不知道是什么,开发者也只能比对每次登录时输入的密码和数据库保存的密码是否一致,判断是否为合法用户,却无法知道密码到底是什么。

用户数据校验流程图

需要说明的是,我们明确说明服务器是没有保存session_key的。因为我们需要拿到session_key才能进行用户数据校验,所以在上述流程图再一次重复了用户的登录流程。在真实的流程中,用户登录在session_key的有效时间内只应该执行一次,session_key也应当被保存在服务器中。其实小程序只需要使用wx.request将rawData和signature发送到服务器即可,服务器无须使用code换取session_key,直接做SHA-1签名比对即可。如图所示为服务器已保存session_key的用户数据校验流程。

如果服务器已保存了session_key的用户数据校验流程

对比服务器没保存session_key和保存了session_key的数据校验流程图,很明显可以看出,服务器保存session_key后整个流程变得更加简单,完全不需要再与微信服务器交互。

服务器管理session_key的过程非常复杂,为了降低代码的复杂度,我们没有在服务器中保存session_key。我们后续的所有开放API调用流程都将重复完整的流程,因为单独完整的流程更加有利于开发者理解每个开放API。下面看下具体代码:

前端代码

wx.login({
	success: function (loginRes){
		wx.getUserProfile({
			success: function (userRes){
				wx.request({
                    url: "http://localhost:8080/wxopen/wxcheckuserinfo"
                    data: {
                        code: loginRes.code,
                        signature: userRes.signature,
                        rawData: userRes.rawData
                    },
                    success: function(res){
                        console.log(res.data);
                    }
                })
			}
		})
	}
})

首先,登录并拿到code码,然后调用wx.getUserProfile接口到rawData和signature,再使用wx.request将这3个参数发送到服务器中,服务器会进行数据校验工作并返回校验结果。下面是服务器接口wxcheckuserinfo的编码。

Map<String,Object> map = new HashMap<>(7);
map.put("appid",wxAppId);
map.put("secret",wxSecret);
map.put("js_code", param.getCode());
map.put("grant_type",grantType);
WxCode2SessionRet result = null;
try{
    String url = "https://api.weixin.qq.com/sns/jscode2session";
    String info = HttpUtil.get(url, map);
    result = JSON.parseObject(info, WxCode2SessionRet.class);
} catch (Exception e){
    log.error("code2session失败", e);
    return null;
}
try {
    String signature2 = DigestUtils.sha1Hex(encryptedData + result.getSession_key());
    if (!signature.equals(signature2)) {
        return R.error().message("签名校验失败");
    }
} catch (Exception e) {
    throw new RuntimeException("用户信息校验失败");
}

WxCode2SessionRet.java

@Data
public class WxCode2SessionRet implements Serializable {
    private String openid;
    private String session_key;
    private String unionid;
    private String errcode;
    private String errmsg;
}

在以上代码中,首先使用code调用微信服务器换取session_key,随后使用session_key和signarue校验用户发送过来的rawData,最后返回校验结果。

建议开发者在客户端使用用户明文数据时使用rawData,而不要使用userInfo。因为数据验证的是rawData有没有被篡改,而不是验证userInfo是否被篡改。至于微信能否确保userInfo和rawData的一致性,这个不得而知。建议开发者使用rawData作为用户的基本信息。

至此,微信小程序获取用户信息、校验用户信息的过程就已经讲完了,下一篇文章我会介绍一下怎么解析用户的加密信息。

总结

  • 用户基本信息有以下7个,他们属于明文

avatarUrl 用户微信头像的URL地址。
city 城市。
country 国家。
gender 性别,1表示男,2表示女,0表示未知。
language 语言区域。
nickName 昵称。
province:省份。

  • 用户加密信息有openId和UnionId,它们是用户在微信应用中的id号

他们的区别是:

1. openId只代表用户在某个微信应用下的id号;
2. 而UnionId是跨应用的,同一用户在同一开发者的多个应用里,UnionId是唯一的。

  • 如何知道明文数据是否被篡改了?通过校验用户加密信息rawData和signature是否一致。signature是使用sha1(rawData+sessionkey)得到的字符串。如果数据没有被篡改,那么signature等于sha1(rawData+sessionkey);如果数据被篡改,则不等于。

  • session_key有什么作用?session_key有点类似于我们在数据库中保存用户密码时所使用的“盐(salt)”。

请联系我

我是IT果果日记,微信公众号请搜索 IT果果日记
一个普通的技术宅,定期分享技术文章,欢迎点赞、关注和转发,请多关照。

微信公众号 IT果果日记

https://gitee.com/chenzhaoplus

https://github.com/chenzhaoplus

https://blog.csdn.net/cz285933169?spm=1010.2135.3001.5421

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/337240.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务项目简介

项目简介 项目模式 电商模式&#xff1a;市面上有5种常见的电商模式&#xff0c;B2B、B2C、 C2B、 C2C、O2O; 1、B2B模式 B2B (Business to Business)&#xff0c;是指 商家与商家建立的商业关系。如:阿里巴巴 2、B2C 模式 B2C (Business to Consumer), 就是我们经常看到的供…

6个月软件测试培训出来后的感悟 —— 写给正在迷茫是否要转行或去学软件测试的学弟们

本人刚从某培训机构学习结束&#xff0c;现在已经上班一个月了。这篇文章我不会说太多的知识点&#xff0c;或噱人去培训机构学习的话语&#xff0c;仅作为一个普通打工者的身份&#xff0c;来写给那些对于软件测试未来发展、薪资待遇等不清楚的正在为家庭&#xff0c;解决信用…

2023年中国数字化活动行业专题报告

易观&#xff1a;2023年2月&#xff0c;易观发布《2023年中国数字化活动行业专题报告》。报告主要分析了中国数字化活动市场发展背景与现状&#xff0c;数字化活动厂商的主要商业模式及其运作模式&#xff0c;典型案例&#xff0c;未来发展趋势洞察等。同时&#xff0c;易观分析…

网上流量卡可靠吗,网上的这些大流量卡你知道是怎么来的吗?

网上怎么这么多五花八门的流量卡&#xff0c;这些大流量卡是怎么来的你都知道吗&#xff1f;所谓的大流量卡&#xff0c;是因为每个省份为了拉新用户所自行包装的产品&#xff0c;一般是在在基础套餐上增加了一些流量包和充值送话费活动&#xff0c;然后得出来一个产品套餐&…

【动态规划】01背包问题(滚动数组 + 手画图解)

01背包除了可以用形象的二维动态数组表示外&#xff0c;还可以使用空间复杂度更低的一维滚动数组。 目录 文章目录 前言 一、滚动数组的基本理解 二、确定dp及其下标含义 三、确定递推公式 四、确定初始化 五、确定遍历顺序 1.用物品&#xff08;正序&#xff09;遍历背…

【刷题篇】链表(上)

前言&#x1f308;前段时间我们学习了单向链表和双向链表&#xff0c;本期将带来3道与链表相关的OJ题来巩固对链表的理解。话不多说&#xff0c;让我们进入今天的题目吧&#xff01;&#x1f680;本期的题目有&#xff1a;反转单链表、链表的中间结点、合并两个有序链表反转单链…

XCP实战系列介绍09-基于Vehicle Spy进行XCP测量步骤详解

本文框架 1.概述2. 基于SPY进行测量步骤2.1 建立ECU和vspy3通信2.2 DAQ数据设置2.3 测量变量的记录2.3.1 需要记录变量的选择2.3.2 Log保存3. 在MEP中观测变量3.1 添加观测变量3.2 实时更新变量的值1.概述 在介绍了ASAP2 Editor进行A2l文件的生成,及如何使用Vehicle Spy进行X…

点云深度学习系列博客(五): Point Transformer方法概述

在上一篇博客《注意力机制原理概述》中&#xff0c;我们介绍了注意力机制的基本原理以及一些技术细节。基于注意力机制的深度学习模型在起初设计时&#xff0c;针对的是NLP问题。包括词元分析&#xff0c;翻译等语言处理任务&#xff0c;注意力机制能够训练超大规模数据&#x…

活动星投票午间修身自习室制作在线投票投票制作网页

“午间修身自习室”网络评选投票_免费小程序投票推广_小程序投票平台好处手机互联网给所有人都带来不同程度的便利&#xff0c;而微信已经成为国民的系统级别的应用。现在很多人都会在微信群或朋友圈里转发投票&#xff0c;对于运营及推广来说找一个合适的投票小程序能够提高工…

SpringBoot整合(三)SpringBoot发送邮件

使用SpringBoot发送邮件 邮件发送其实是一个非常常见的需求&#xff0c;用户注册&#xff0c;找回密码等地方&#xff0c;都会用到&#xff0c;Spring Boot 中对于邮件发送&#xff0c;提供了相关的自动化配置类&#xff0c;使得邮件发送变得非常容易。 1、前置工作 目前国内…

[SSD固态硬盘技术 9] FTL详解

了解硬件特性有助于我们针对特性进行进一步的探索与优化。为了使闪存成为存储数据的友好介质&#xff0c;我们需要一种机制&#xff1a;将更新的信息写入新的空页&#xff0c;然后将 所有后续读取请求转移到其新地址确保新编程的页面均匀分布在所有可用闪存中&#xff0c;以便均…

【Python入门第五天】Python 变量

创建变量 变量是存放数据值的容器。 与其他编程语言不同&#xff0c;Python 没有声明变量的命令。 首次为其赋值时&#xff0c;才会创建变量。 实例 x 10 y "Bill" print(x) print(y)运行实例 变量不需要使用任何特定类型声明&#xff0c;甚至可以在设置后更改…

Jupyter 使用Anaconda 虚拟环境内核

Anaconda 虚拟环境中使用Jupyter Notebook 安装好Anaconda之后&#xff0c;进入Anaconda Prompt&#xff0c;创建虚拟环境&#xff0c;env_name是创建的环境的名字。 conda creat -n env_name python3.9等虚拟环境搭建好之后&#xff0c;激活环境。 conda activate env_name…

网络流与图(一)

线性规划问题是运筹学最基本的问题&#xff0c;我们已经学过不少的解决方法&#xff0c;今天继续学习针对线性规划问题的另一种高效算法——网络流问题&#xff08;network flow problem&#xff09;1网络流模型为了更好介绍该算法来龙去脉&#xff0c;与以往一样&#xff0c;从…

MongoDB 删除文档

MongoDB 删除文档 MongoDB remove() 、deleteMany()、deleteOne()函数是用来移除集合中的数据。 remove()删除文档 remove() 方法的基本语法格式如下所示&#xff1a; db.collection.remove(<query>,<justOne> ) 如果你的 MongoDB 是 2.6 版本以后的&#xff0c…

filter及backdrop-filter属性详解

filter属性详解 filter 属性定义了元素(通常是<img>)的可视效果(例如&#xff1a;模糊与饱和度)。 filter: none | blur() | brightness() | contrast() | drop-shadow() | grayscale() | hue-rotate() | invert() | opacity() | saturate() | sepia() | url();下面运用…

聚观早报 |字节开展类ChatGPT研究;特斯拉前AI负责人将加入OpenAI

今日要闻&#xff1a;字节开展类ChatGPT研究&#xff1b;丰田汽车第三财季净利润同比下降8.1% 特斯拉前AI负责人将加入OpenAI&#xff1b;快手&#xff1a;正在开展大规模语言模型研究&#xff1b;劳斯莱斯CEO称客户希望更多电动汽车 字节开展类ChatGPT研究 北京时间 2 月 9 日…

零代码做分析报表的bi软件才是好软件

有些数据分析软件对IT的依赖比较重&#xff0c;在制作报表的过程中需要用到SQL&#xff0c;这就导致了IT人员懂技术不懂业务&#xff0c;业务人员懂业务不懂技术&#xff0c;数据分析做来做去总是差点什么的局面。要是遇到了IT部门相对较弱的情况&#xff0c;还会加重IT负担&am…

字符串函数能有什么坏心思?

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;夏目的C语言宝藏 &#x1f4ac;总结&#xff1a;希望你看完之…

又发现一个ChatGPT国内镜像站,无次数限制也无广告

ChatGPT 美国OpenAI研发的聊天机器人程序&#xff0c;于2022年11月30日发布。ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过学习和理解人类的语言来进行对话&#xff0c;还能根据聊天的上下文进行互动&#xff0c;真正像人类一样来聊天交流&#xff0c;…