小程序用户信息的获取流程

3,581 阅读4分钟

获取用户信息小程序登录是息息相关的。所以先讨论小程序登录

小程序登录

小程序登录的具体流程,在官方文档中描述的非常清楚。这里主要阐述一下对codesession_key的理解。

微信小程序登录流程图

流程图中可以发现,整个流程的第一步是在微信小程序中通过wx.login()方法获取code,然后将该code传给后端,后端拿着这个code调用auth.code2Session接口获取session_keyopenid

code使用一次之后就会失效,而对于session_key的作用,文档也给出了很好的说明:

会话密钥session_key是对用户数据进行加密签名的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。

从这句话可以看出,由code转换为session_keyopenid是为了安全性考虑(真是一句废话),打个比方呢,就像初始密码与修改密码差不多的道理吧。

另外可知,对于开发者来说,session_key主要是为了解密用的,那么要对什么进行解密?又要如何解密呢?这里通过获取手机号这一业务场景进行说明。

获取手机号

在小程序中获取手机号的具体步骤,在官方文档文档中也有很好的描述(也许我就是懒得写吧)。这里主要说一下session_key的处理以及加密与解密的过程。

在小程序中,通过将button组件open-type的值设置为getPhoneNumber后,获得的手机号信息并不是13811111111这样的明文,而是两个加密之后的字段:

参数 类型 说明
encryptedData String 包括敏感数据在内的完整用户信息的加密数据
iv String 加密算法的初始向量

具体加密解密流程

小程序开发者:腾讯大爷,用户已经授权给我手机号啦,现在可以发我吗?

腾讯:等会,我用session_key加密一下,好啦,给你

小程序开发者:我靠,这一堆乱码,后端大哥,帮解密一下呗

后端大哥:解密可以,但是我这里没有session_key,给我个code

小程序开发者:好嘞,wx.login(),走你。

后端大哥:调用auth.code2Session接口,耶!session_key到手,现在可以给我encryptedDataiv了。

小程序开发者:嗯,再走你。

balabala...

后端大哥:解密好了,手机号13811111111。

重点讨论

整个过程最重要的是session_key获取的时机,因为如果微信加密的session_key与后端解密的session_key不是同一个的话,是无法解密的,在官方文档中也有很好的说明:

在回调中调用wx.login登录,可能会刷新登录态。此时服务器使用code换取的 sessionKey不是加密时使用的sessionKey,导致解密失败。建议开发者提前进行 login;或者在回调中先使用checkSession进行登录态检查,避免login刷新登录态。

可见,有两种处理方式,按照时间发生的时序,描述如下:

方式一

  1. 小程序调用wx.login()获取code并发起请求A,将code传到后端;
  2. 后端获取session_key,并对请求A做出响应;
  3. 小程序收到请求A的响应后,才能允许用户点击获取手机号的button(可在发起请求的过程中,一直loading,防止用户点击);
  4. 用户点击button,获取加密的手机号信息;
  5. 调用解密手机号的接口。

方式二

  1. 用户点击button获取加密的手机号信息;
  2. bindgetphonenumber的回调函数中,调用wx.checkSession()方法,检测当前用户登录态是否有效。
    1. 如果有效(success回调函数执行),则说明后端之前已经获取过session_key,并且是有效的。直接调用解密手机号的接口。
    2. 如果无效(fail回调函数执行),则需要先调用wx.login()获取code并发起请求B,后端获取有效的session_key后,响应请求B,然后小程序在请求B的回调中调用解密手机号的接口。

而上方的具体加密解密流程,描述的就是方式二的处理过程。

当然,同时结合这两种方式一起使用,是最保险的方式啦。

最后贴一下方式二的代码:

<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">Click Me</button>>
function getPhoneNumber(e) {
    const {encryptedData, iv} = e.target;
    
    wx.checkSession({
        success: () => {
            // 调用解密手机号的接口
            decodePhoneNumber({encryptedData, iv});
        },
        fail: () => {
            wx.login({
                success: (res)=>{
                    // 更新session_key的接口
                    getSession(res.code).then(() => {
                        // 调用解密手机号的接口
                        decodePhoneNumber({encryptedData, iv});
                    });
                }
            });
        }
    })
}

以上。End。