WeChat Mini プログラムがユーザー情報を取得する方法

自己紹介

私は IT 国国日記です. WeChat 公式アカウントで IT 国国日記を検索してください. 私は定期的に技術記事を共有している普通の技術
オタク . いいね, フォロー, 再投稿を歓迎します. よろしくお願いします.
  • WeChat Mini Program ユーザーの基本情報は?

  • WeChatは基本情報の他にopenIdとunionIdを提供していますが、それぞれの機能と違いは何ですか?

  • ユーザー情報を取得する過程で、平文データが改ざんされているかどうかをどのように知ることができますか?

  • session_key の使用方法

これらの質問を念頭に置いて、今日の研究を開始します。

ユーザーの基本情報を取得する

アプレットは、ユーザー情報を取得するwx.getUserProfile(OBJECT)メソッドを提供します。以前の古いバージョンは wx.getUserProfile(OBJECT) メソッドを使用していましたが、これは現在公式に廃止されています。

ユーザー情報は、基本ユーザー情報、ユーザーopenId、UnionIdに分けられます。基本情報はプレーンテキストですが、openId と UnionId は暗号化されたデータです。どちらのタイプのデータも wx.getUserProfile(OBJECT) メソッドによって返されます。

ユーザー基本情報には、次の7項目が含まれます。

  • avatarUrl ユーザーの WeChat アバターの URL アドレス。

  • 都市都市。

  • 国の国。

  • 性別。1 は男性、2 は女性、0 は不明を意味します。

  • 言語ロケール。

  • ニックネーム ニックネーム。

  • 州: 州。

アプレットでは、ユーザーの基本情報を簡単に取得でき、それらは平文で暗号化されていません。ただし、openIdUnionId は暗号化されています。openId と UnionId とは何ですか? OpenId と UnionId は、WeChat アプリケーションでのユーザーの ID 番号として理解できます。

それらの違いは次のとおりです。

  • openId は、特定の WeChat アプリケーションでのユーザーの ID 番号のみを表します。

  • UnionId はアプリケーション間であり、UnionId は同じ開発者の複数のアプリケーションで同じユーザーに対して一意です。

公式ドキュメントの UnionId の説明は非常に明確です。開発者が複数のモバイル アプリケーション、Web サイト アプリケーション、パブリック アカウント (アプレットを含む) を持っている場合、ユーザーの一意性は UnionId によって区別できます。同じ WeChat オープン プラットフォーム アカウント アプリケーション、Web サイト アプリケーション、およびパブリック アカウント (アプレットを含む) の場合、ユーザーの UnionId は一意です。つまり、同じユーザーは、同じ WeChat オープン プラットフォームの異なるアプリケーションで同じ UnionId を持っています。

したがって、openId はアプリケーションをまたがることはできません。複数のアプリケーション間でユーザー ID を統一する場合は、UnionId を使用してください。ここで、アプレットで UnionId を使用するには、まず WeChat オープン プラットフォームにアクセスしてアプレットをバインドする必要があることに注意してください。公式ドキュメントを参照してください。

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

WeChat オープン プラットフォーム バインディング ミニ プログラム プロセス

WeChat Open Platformにログイン—Management Center—Mini Programs—Binding Mini Programs

WeChat オープン プラットフォーム バインディング アプレット

wx.getUserProfile(OBJECT) メソッドの使用法を見てみましょう。wx.getUserProfile の OBJECT パラメータには、成功、失敗、完了の 3 つのコールバック関数があります。これら 3 つのコールバック関数の中で、成功に焦点が当てられています。success メソッドの戻り値には、次の 5 つの値があります。

  • userInfo 基本的なユーザー情報オブジェクト。openId などの機密情報は含まれません。

  • rawData は、機密情報を含まない基本的な情報文字列であり、通常、WeChat から返されるユーザー情報の改ざんを防ぐために署名を計算するために使用されます。

  • 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;
	}
}

上記のコードを説明してください。ミニプログラムが開始されるたびにWeChatサーバーにユーザーの基本情報をロードすることを避けるために、ユーザー情報をキャッシュに保存します。このように、アプレットを起動するたびに、まずキャッシュにデータがあるかどうかを確認し、ない場合は 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 の成功コールバック関数が実行され、ユーザーが「拒否」をクリックすると、失敗コールバック関数が実行されます。

一部の開発者は、テスト時にこの認証ウィンドウをポップアップ表示しない場合があります。現在のプロジェクトに appId がない場合、ユーザー情報は WeChat によってシミュレートされ、ユーザー情報を取得する実際のプロセスがないため、このウィンドウは表示されず、開発ツールには次のように警告プロンプトが表示されます。図。

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

おすすめ

転載: blog.csdn.net/cz285933169/article/details/128978495