小程序可以通过微信官方提供的登录方法方便地获取微信提供的用户身份标识,进而开发者可以进行下一步操作。
1、调用 wx.login()接口获取临时登录凭证code(用户登录凭证,有效期5分钟,code 只能使用一次,使用一次后失效)。
2、服务端拿到code,调用 auth.code2Session接口,获取用户唯一标识openId 、用户在开放平台的唯一标识符unionid,会话密钥 session_key。
其中,会话密钥 session_key 是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。
3、通过openId和session_key可以自定义服务端,判断用户登录状态。
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为头像的链接。
调试时返回的数据:
进而从返回的数据中,可以拿到用户的微信昵称、性别、城市以及微信头像等。
开发者如果遇到因为 session_key 不正确而校验签名失败或解密失败,请关注下面几个与 session_key 有关的注意事项。
获取用户手机号和获取用户信息大致一样的操作
需要用户主动触发才能发起获取手机号接口,所以该功能不由 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