python实现小程序登录及获取用户信息和手机号

小程序登录:

       小程序可以通过微信官方提供的登录方法方便地获取微信提供的用户身份标识,进而开发者可以进行下一步操作。

登录流程:

python实现小程序登录及获取用户信息和手机号_第1张图片

        1、调用 wx.login()接口获取临时登录凭证code(用户登录凭证,有效期5分钟,code 只能使用一次,使用一次后失效)。

        2、服务端拿到code,调用 auth.code2Session接口,获取用户唯一标识openId 、用户在开放平台的唯一标识符unionid,会话密钥 session_key。

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

        3、通过openId和session_key可以自定义服务端,判断用户登录状态。

 

获取用户信息

 

                                     python实现小程序登录及获取用户信息和手机号_第2张图片

        1、用户授权后,小程序通过请求auth.code2Session()接口,从接口返回的内容中拿到用户信息,敏感信息被加密。

auth.code2Session()接口请求地址:

GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

请求参数:

属性

类型

必填

说明

appid

string

小程序 appId

secret

string

小程序 appSecret

js_code

string

登录时获取的 code

grant_type

string

授权类型,此处只需填写 authorization_code

其中小程序 appId和小程序 appSecret是在小程序管理平台上获取的,不会改变的,可以写在配置文件中。

返回的json数据包:

属性

类型

说明

openid

string

用户唯一标识

session_key

string

会话密钥

unionid

string

用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回,详见 UnionID 机制说明。

errcode

string

错误码

errmsg

string

错误信息

返回的加密信息参数说明:

参数

类型

说明

encryptedData

String

包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法

iv

String

加密算法的初始向量,详细见加密数据解密算法

cloudID

String

敏感数据对应的云 ID,开通云开发的小程序才会返回,可通过云调用直接获取开放数据

        2、把加密的信息传给服务端,同时使用在登录时获取的session_key以及appId进行解密数据(将加密信息参数encryptedData和iv,以及在登录时获取的session_key和appId 传入WXBizDataCrypt.py程序进行解密),获取用户相关信息,主要包括微信名、性别、头像等。其中解密方法可以查看微信的开放数据校验和解密文档。

 

python3对加密信息进行解密代码

WXBizDataCrypt.py:

import base64
import json
from Crypto.Cipher import AES

class WXBizDataCrypt:
    def __init__(self, appId, sessionKey):
        self.appId = appId
        self.sessionKey = sessionKey

    def decrypt(self, encryptedData, iv):
        # base64 decode
        sessionKey = base64.b64decode(self.sessionKey)
        encryptedData = base64.b64decode(encryptedData)
        iv = base64.b64decode(iv)

        cipher = AES.new(sessionKey, AES.MODE_CBC, iv)

        decrypted = json.loads(self._unpad(cipher.decrypt(encryptedData)))

        if decrypted['watermark']['appid'] != self.appId:
            raise Exception('Invalid Buffer')

        return decrypted

    def _unpad(self, s):
        return s[:-ord(s[len(s)-1:])]

获取用户信息代码如下: 

# 解密获取用户信息
def decrypt_encrypteddata(self,session_key,encryptedData,iv):
    decrypt_data = WXBizDataCrypt(APPID, session_key)
    decrypt_data = decrypt_data.decrypt(encryptedData, iv)
    return decrypt_data 

 



        # 登录接口
    def get_VistorInfo(self, request_data):
        """
        通过参数APPID, SECRET, js_code获取到用户的微信唯一标识openID和sessionKey
        通过参数encryptedData 、iv 、sessionKey 请求后台解密获取用户信息
        :param request_data: 请求参数包含encryptedData,iv,code
        :return:
        """
        try:
            database = DataBase()
            encryptedData = request_data.get('encryptedData')
            iv = request_data.get('iv')
            url_code2Session = "https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}" \
                               "&grant_type=authorization_code".format(APPID, SECRET, request_data.get('code'))
            data = requests.get(url_code2Session)
            if data.status_code == 200:
                data_content = json.loads(data.content)
                if 'session_key' in data_content:
                    session_key = data_content['session_key']
                    user_info = self.decrypt_encrypteddata(session_key, encryptedData, iv)
                    open_id = user_info.get('openId')                     # 微信用户唯一标识
                    session['open_id'] = open_id   #将微信唯一标识open_id存在session中
                    session['session_key'] = session_key #将session_key存在session中
                    #这里是自己的逻辑实现,例如将用户信息存储到数据库中
                    #这里是自己的逻辑实现,例如将用户信息存储到数据库中
                    #这里是自己的逻辑实现,例如将用户信息存储到数据库中
                    res =  {'code': 1, 'message': '用户已登录'}
                else:
                    res = {'code': 2, 'message': '用户未登录'}
            else:
                res = {'code': 2, 'message': '用户未登录'}
            return res
        except Exception as e:
            error_info = '用户登录失败:{}'.format(e)
            logger.error(error_info)
        finally:
            database.closeConn()

加密数据解密算法微信官方提供了多种编程语言的示例代码

解密后返回的数据json格式如下:

{
    "openId": "OPENID",
    "nickName": "NICKNAME",
    "gender": GENDER,
    "city": "CITY",
    "province": "PROVINCE",
    "country": "COUNTRY",
    "avatarUrl": "AVATARURL",
    "unionId": "UNIONID",
    "watermark":
    {
        "appid":"APPID",
        "timestamp":TIMESTAMP
    }
}

其中avatarUrl为头像的链接。

调试时返回的数据:

python实现小程序登录及获取用户信息和手机号_第3张图片

进而从返回的数据中,可以拿到用户的微信昵称、性别、城市以及微信头像等。

 

会话密钥 session_key 有效性:

开发者如果遇到因为 session_key 不正确而校验签名失败或解密失败,请关注下面几个与 session_key 有关的注意事项。

  1. wx.login 调用时,用户的 session_key 可能会被更新而致使旧 session_key 失效(刷新机制存在最短周期,如果同一个用户短时间内多次调用 wx.login,并非每次调用都导致 session_key 刷新)。开发者应该在明确需要重新登录时才调用 wx.login,及时通过 auth.code2Session 接口更新服务器存储的 session_key。
  2. 微信不会把 session_key 的有效期告知开发者。我们会根据用户使用小程序的行为对 session_key 进行续期。用户越频繁使用小程序,session_key 有效期越长。
  3. 开发者在 session_key 失效时,可以通过重新执行登录流程获取有效的 session_key。使用接口 wx.checkSession可以校验 session_key 是否有效,从而避免小程序反复执行登录流程。
  4. 当开发者在实现自定义登录态时,可以考虑以 session_key 有效期作为自身登录态有效期,也可以实现自定义的时效性策略。

 

获取用户手机号

获取用户手机号和获取用户信息大致一样的操作

                                     python实现小程序登录及获取用户信息和手机号_第4张图片

        需要用户主动触发才能发起获取手机号接口,所以该功能不由 API 来调用,需用前端组件点击进行触发。可查看获取手机号文档。

        1、小程序通过点击触发getPhoneNum事件,当用户点击并同意之后,获得加密后的信息;

代码示例:

Page({
  getPhoneNumber (e) {
    console.log(e.detail.errMsg)
    console.log(e.detail.iv)
    console.log(e.detail.encryptedData)
  }
})

返回的加密信息:

参数

类型

说明

encryptedData

String

包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法

iv

String

加密算法的初始向量,详细见加密数据解密算法

cloudID

String

敏感数据对应的云 ID,开通云开发的小程序才会返回,可通过云调用直接获取开放数据

        2、把加密信息传给服务端,使用在登录时获取的session_key以及appId进行解密数据,获取微信用户绑定的手机号。

将加密信息参数encryptedData和iv,以及在登录时获取的session_key和appId 传入WXBizDataCrypt.py程序进行解密。

解密后返回的数据json结构如下:

{
    "phoneNumber": "13580006666",
    "purePhoneNumber": "13580006666",
    "countryCode": "86",
    "watermark":
    {
        "appid":"APPID",
        "timestamp": TIMESTAMP
    }
}

        其中,phoneNumber为用户绑定的手机号(国外手机号会有区号);purePhoneNumber为没有区号的手机号;countryCode为区号。

进而从返回的数据中,可以拿到用户微信绑定的手机号。

获取手机号代码如下:

 # 获取用户手机号
    def get_phone(self, request_data):
        """
         通过参数encryptedData 、iv 、sessionKey 请求后台解密获取用户手机号
        :param request_data:
        :return:
        """
        try:
            database = DataBase()
            if 'session_key' in session and session['session_key']:
                session_key = session['session_key']
                open_id = session['open_id']
                phone_info = self.decrypt_encrypteddata(session_key, request_data.get('encryptedData'), request_data.get('iv'))
                phone_number = phone_info.get('phoneNumber')
                sql = """ """
                database.insertSql(sql)
                res = {'code': 1, 'message': '操作完成'}
                return res
            else:
                res = {'code': 2, 'message': '用户未登录'}
                return res
        except Exception as e:
            error_info = '获取手机号出错:{}'.format(e)
            logger.error(error_info)
        finally:
            database.closeConn()

注意:

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

        总结流程:首先通过请求参数APPID, SECRET, js_code获取到用户的微信唯一标识openID和sessionKey;再通过参数encryptedData 、iv 、sessionKey 请求后台接口解密用户信息;最后从返回的json数据中,取出用户信息或者手机号。 

 

参考:https://developers.weixin.qq.com/miniprogram/dev/api/

          https://www.cnblogs.com/chaohangz/p/9969164.html

你可能感兴趣的:(Python后端)