开发微信小程序时,接入小程序的授权登录可以快速实现用户注册登录的步骤,是快速建立用户体系的重要一步。这篇文章将介绍 python + flask + 微信小程序实现用户快速注册登录方案(本文主要进行后端逻辑的梳理,小程序端逻辑只写了必要的部分,如有需要,请点击连接阅读官方开发文档)
官方给出的微信小程序登录时序图如下:
这个流程分为两大部分:
小程序端可以通过 wx.getSetting 接口获取用户当前的授权状态
引导用户关注公众号 来获得授权。小程序通过wx.login获取微信的 code,然后将这个 code 发送给开发者服务器。
返回值
| 属性 | 类型 | 说明 |
|---|---|---|
| code | String | 用户允许登录后,回调内容会带上 code(有效期五分钟) |
小程序端调用 wx.getUserInfo API 来获得用户信息(该接口的调用需要获得用户授权)
接口success 时返回参数如下:
| 参数名 | 类型 | 说明 |
|---|---|---|
| userInfo | OBJECT | 用户信息对象,不包含 openid 等敏感信息。 |
| rawData | String | 不包括敏感信息的原始数据字符串,用于计算签名。 |
| signature | String | 使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息 |
| encryptedData | String | 包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法 |
| iv | String | 加密算法的初始向量,详细见加密数据解密算法 |
将这些第一步获得的js_code和这里获得的 rawData, signature, encryptedData, iv一起打包传入开发者后端。
开发者服务器接收到 code 之后,会进行封装处理,通过code2Session这个api接口来获取真正需要的微信用户的登录态session_key和 openid 和 unionid。
session_key才是真正的微信登录态信息,但是把 openid 和 unionid加起来一起理解,也可以笼统地理解为这些都是微信的登录态信息。请求参数
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
| appid | string | 是 | 小程序 appId | |
| secret | string | 是 | 小程序 appSecret | |
| js_code | string | 是 | 登录时获取的 code | |
| grant_type | string | 是 | 授权类型,此处只需填写 authorization_code |
返回值(返回JSON数据包)
| 属性 | 类型 | 说明 |
|---|---|---|
| openid | string | 用户唯一标识 |
| session_key | string | 会话密钥 |
| unionid | string | 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回 |
| errcode | number | 错误码 |
| errmsg | string | 错误信息 |
这时,服务器需要判断返回的JSON数据包是否包含unionid:
encryptedData 解密后为以下 json 结构,详见加密数据解密算法
{
"openId": "OPENID",
"nickName": "NICKNAME",
"gender": GENDER,
"city": "CITY",
"province": "PROVINCE",
"country": "COUNTRY",
"avatarUrl": "AVATARURL",
"unionId": "UNIONID",
"watermark":
{
"appid":"APPID",
"timestamp":TIMESTAMP
}
}
解密脚本实例连接:https://res.wx.qq.com/wxdoc/dist/assets/media/aes-sample.eae1f364.zip
为了确保开放接口返回用户数据的安全性,微信会对明文数据进行签名。开发者可以根据业务需要对数据包进行签名校验,确保数据的完整性。
code 为空,返回登录失败。code 不为空,且 rawData 不为空,需要进行签名校验:
code,appid、app_secret 请求code2session接口获得 session_key 和 openid
ERR_SESSION_KEY_EXCHANGE_FAILEDrawData 和 session_key 计算签名 signature2signature 和 signature2
ERR_UNTRUSTED_RAW_DATArawData 为 wxUserInfo
openid 写入到 wxUserInfo(code, wxUserInfo) 缓存到 Rediscode 不为空,但 rawData 为空,从 Redis 根据 code 查询缓存的用户信息
ERR_SESSION_EXPIRED开发者服务器需要自己生成一个自定义的登录态(例如业务 token或者 session)来保存这些微信服务器返回来的微信登录态相关信息(session_key和 openid 和 unionid),并且做关联处理,然后返回给小程序客户端。
小程序客户端接收到返回的自定义登录态信息,从而判断用户是否登录成功,登录成功的话,就将自定义登录态信息保存到本地的存储。到这里,登录就完成了。
app.globaldata,也可以是 localstoage,注意,小程序不支持 cookie。小程序客户端访问业务接口的时候,携带之前保存到本地存储的自定义登录态信息进行对开发者服务器(业务接口服务器)访问。
开发者服务器的业务接口接收到请求,并且请求里面携带了自定义的登录态,通过校验之后,会返回相关信息。
校验登录是将小程序客户端携带过来的自定义登录态和开发者服务器缓存起来的自定义登录态进行对比,会去确认是否和用户的 openid或者 unionid 和 session_key 相匹配。
code2Session进行微信登录态更新。由于我们的小程序使用微信号作为小程序的账号,如果需要使用自定义的账号,则需要再加上注册的api和关联账号的逻辑。
code 是微信用户的登录临时凭证,是打开小程序登录的时候获取的只属于这个微信用户的登录凭证,需要注意的是,这个登录凭证只供微信小程序使用的。且同一个每一次登录时获得的code都不同。这个 code 的存活时间一般是5分钟左右,他的最大作用就是确定是来源自哪一个微信用户来打开,是为了后续生成一个微信登录态 session_key而准备的。session_key 是微信用户在小程序里面的登录态信息,这是微信给这个用户颁发的一个登录 session。这个session 一直存活直到你关闭小程序。
expire_time 的,但是后面取消了,官方的解释是:用户越频繁使用小程序,session_key有效期越长,初始有效期是3天,但是这个不一定是固定的,具体看业务需求,总的原则就是维护一个自定义登录态,自定义登录需要和微信登录态关联。openId ,用户在微信里面的唯一标识,但是需要跟 unionid 进行一起理解。unioinId,如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。
openId 就是微信用户的唯一标识,但是因为微信产品很多,所以会出现多个微信产品使用不同的 openId 来识别同一个用户,所以建议是统一使用 unioinid 作为用户识别的依据,因为一般来说,一般的业务都会有公众号,所以 unionid 使用频率较高。3rd_session 是一般是指开发者服务器的登录态,也就是自定义登录态。
wx.checkSession来检查,如果过期了,就本地执行登录操作,再让开发者服务器跟微信服务器交互,获取新的小程序登录态,然后关联到自定义登录态。如果每次打开小程序都需要用户来登录显然是不合适的,如果用户上一次的登录态还没有过期,则应该视用户为已经登录。如果过期,才需要用户重新登录。
有2种方式来做:
wx.checkSession检查微信登录态是否过期:
某些业务需要只有用户登录状态下才可以执行,所以,我们需要封装一个api来验证用户时候登录
实际上就是检查一下微信和自定义的登录态是否过期
官方教程:手把手教会你小程序登录鉴权
微信小程序开发:python+sanic 实现小程序登录注册
小程序开发-梳理登录流程
理解JWT(JSON Web Token)认证及实践