如何实现
经过一番思考和调研,我确定以下方式是可行的
利用生成小程序码的接口wxacode.getUnlimited,我们可以生成无限个数的小程序码,虽然该接口携带参数有些限制,但不影响整个逻辑的实现。
扫小程序码登录逻辑如下:
核心技术点
生成时间戳签名
Web端生成的时间戳签名必须得是唯一的,如果出现不唯一的签名,用户登录就会乱套了。而生成小程序码所使用的
getUnlimited
接口仅允许携带一个scene
参数,长度要求为32个字符以内。
保证唯一性有很多GUID/UUID的方案,但在本例里,小程序码携带参数的字符数量是有限制的,所以常见方案都不太适合。我最后找到的是nanoid这个方案,非常符合我的需求。
/* 一个小巧、安全、URL友好、唯一的 JavaScript 字符串ID生成器。 “一个惊人的无意义的完美主义水平, 这简直让人无法不敬佩。” **小巧.** 130 bytes (已压缩和 gzipped)。 没有依赖。 [Size Limit](https://github.com/ai/size-limit) 控制大小。 **快速.** 它比 UUID 快 60%。 **安全.** 它使用加密的强随机 API。可在集群中使用。 **紧凑.** 它使用比 UUID(`A-Za-z0-9_-`)更大的字母表。 因此,ID 大小从36个符号减少到21个符号。 **易用.** Nano ID 已被移植到 [19种编程语言](https://github.com/ai/nanoid/blob/main/README.zh-CN.md#%E5%85%B6%E4%BB%96%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80)。 */ import { nanoid } from 'nanoid' model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
生成小程序码
这里需要注意的是,我们在web端里通过调用生成小程码的接口,将最终的小程序码显示在网页里。
scene
是一个不可变的参数名,参数内容里放的是时间戳签名。
async function getWXACodeUnlimited(scene,page){ const access_token = await getAccessToken(); const res = await uniCloud.httpclient.request("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+access_token,{ method:"POST", headers:{ "Content-Type":"application/json" }, data:{ scene:scene, page:page } }); return res.data; }
- 扫描小程序码获取签名
使用微信扫描小程序码后,会进入到小程序并打开指定的
page
(小程序内页面),在该页面的onLoad
事件中可以拿到scene
参数。
onLoad(options) { var scene = options.scene; var loginToken; if(scene){ loginToken = scene; } wx.login({ success: (res) => { cloudApi.callFunction({ name:"users", data:{ action:"login", code:res.code, logintoken:loginToken }, success: (res) => { } }) } }) }
上述代码中实现的是,通过login
接口获取到code
,用于请求code2session
接口换取小程序用户的openid
,这一步完成,我们等于就在小程序里完成了用户登录。
然后怎么把信息同步给Web端呢?就是这个LoginToken
,我这里把它写到与openid
相同的用户表数据条目中,然后web端会通过loginToken
轮询这个用户数据表,发现匹配数据后返回给Web
端,完成Web
端的登录
if(loginToken){ await db.collection("users").where({ openid:dbCmd.eq(openid) }).update({ lastlogin:Date.now(), loginToken:dbCmd.set({ value:loginToken, expiretime:Date.now()+60*3*1000000 }) }) }
现在我们已经完成了扫小程序码登录机制,用户登录网站时,也可以增加小程序的用户和日活跃用户数。
轮询优化
- 点击登录时生成并显示小程序码,此时开启轮询,每5秒查询一次数据库。
- 查询到匹配的用户信息,结束轮询,完成登录。
- 在三分钟内如果查询不到匹配的用户信息,结束轮询。