小程序微信登陆及账号绑定功能开发笔记
目标功能:
- 进入小程序后请求获取用户信息用于登录
- 将获取到的用户信息与数据库中的信息进行比对
- 数据合格(能在数据库中找到用户的信息)则进入主页
- 数据不合格(找不到)则提示绑定教职工号,并跳转到绑定界面
- 绑定界面将用户输入的账号和密码与数据库中的记录进行比对,账号和密码确认无误后,将当前的用户信息存入数据库,下次用户登录时直接在数据库中找用户的信息
一、用什么来识别用户?
有两个选择,一个是OpenID,另一个是UnionID。
它们的区别在于:
- OpenID与公众号挂钩,一个用户在一个公众号里只有一个OpenID,但是该用户在不同的公众号里的OpenID不一样,不适用于跨公众号、跨平台等场景的使用,有OpenID不一样的风险。
- UnionID是用户唯一的,跨公众号、跨平台也不会变,可以在用户管理-获取用户基本信息(UnionID机制)文档了解详情。
二、实现方法
(一)UnionID
1、UnionID 机制说明
如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过 UnionID 来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的 UnionID 是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,UnionID是相同的。
2、UnionID获取途径
绑定了开发者帐号的小程序,可以通过以下途径获取 UnionID。
- 开发者可以直接通过 wx.login +
code2Session
获取到该用户 UnionID,无须用户授权。 - 小程序端调用云函数时,可在云函数中通过 Cloud.getWXContext 获取 UnionID。
3、微信开放平台绑定小程序流程
登录微信开放平台 — 管理中心 — 小程序 — 绑定小程序
4、小结
我们当前的小程序无法通过微信认证,因为是个人号。
即使我自己在开放平台注册了一个主体,也无法将其与我们的小程序绑定。
但是我可以绑定我自己的小程序。
也就是说,我们 可以用UnionID ,但是要 郑 在 开放平台 去 注册 一个 账号 ,然后才能与我们的小程序 绑定 。
(二)OpenID
1、流程
- wx.login() 获取 code
- wx.request() 发送 code
- appid + appsecret + code 登录凭证校验接口
- 接口返回 session_key + openid 等
2、注意事项
- 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
- 临时登录凭证 code 只能使用一次
- 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 、 用户在微信开放平台帐号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台帐号) 和 会话密钥 session_key。
3、session_key有什么用
A. session_key 有两个作用:
- 校验用户信息(wx.getUserInfo(OBJECT)返回的signature)
- 解密(wx.getUserInfo(OBJECT)返回的encryptedData)
B. 按照官方的说法,wx.checksession是用来检查 wx.login(OBJECT) 的时效性,判断登录是否过期;
疑惑的是(openid,unionid )都是用户唯一标识,不会因为wx.login(OBJECT)的过期而改变,所以要是没有使用x.getUserInfo(OBJECT)获得的用户信息,确实没必要使用wx.checksession()来检查wx.login(OBJECT) 是否过期;
如果使用了wx.getUserInfo(OBJECT)获得的用户信息,还是有必要使用wx.checksession()来检查wx.login(OBJECT) 是否过期的,因为用户有可能修改了头像、昵称、城市,省份等信息,可以通过检查wx.login(OBJECT) 是否过期来更新着些信息。
三、版本进化
现有bug:
- 开发模拟时可以正常显示,但是,真机调试时以及小程序发布出来正式使用时,无法显示头像和昵称,显示的是默认头像和“微信用户”
- 多次进入小程序则可以直接进入主页,而跳过判断绑定这一步
问题分析
下图是示例小程序的示例代码以及我的代码
可以发现,获取方式是一样的,但是传参方式不一样,那么会不会是这里的问题呢?
2022-04-26更新:完整实现
(功能早就实现了,一直没更新博客)
- 创建云函数login,通过云函数操作才有权限获取到openid
// 云函数模板
// 每次修改代码之后都要保存并部署:在 cloud-functions/login 文件夹右键选择 “上传并部署:安装云端依赖(不上传node_modules)”
const cloud = require('wx-server-sdk')
// 初始化 cloud
cloud.init({
// API 调用都保持和云函数当前所在环境一致
env: cloud.DYNAMIC_CURRENT_ENV
})
/**
* 这个示例将经自动鉴权过的小程序用户 openid 返回给小程序端
*
* event 参数包含小程序端调用传入的 data
*
*/
exports.main = async (event, context) => {
console.log(event)
console.log(context)
// 可执行其他自定义逻辑
// console.log 的内容可以在云开发云函数调用日志查看
// 获取 WX Context (微信调用上下文),包括 OPENID、APPID、及 UNIONID(需满足 UNIONID 获取条件)等信息
const wxContext = cloud.getWXContext()
return {
event,
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
env: wxContext.ENV,
}
}
- 调用云函数login,并对获取到的结果进行操作,存入全局变量可以便于后续使用
wx.cloud.callFunction({
name: 'login',
complete: res => {
// 将获取到的openid存入全局变量中
app.globalData.openId = res.result.openid
console.log(app.globalData.openId)
app.globalData.haveOpenId = true
// 判断数据库中是否已经有数据
DB.collection('user').where({
_openid: app.globalData.openId,
}).get({
success: res => {
console.log(res)
if (res.data.length == 0) {
// 没找到数据
wx.reLaunch({
url: '/pages/register/register',
})
} else {
// 找到了数据
wx.reLaunch({
url: '/pages/home/home?registered=' + true,
})
}
}
})
}
})
- 上面的代码还用到了页面传参的功能,之所以增加这个功能是因为发布小程序时审核不通过,提示要我修改成未注册用户也能体验部分功能才可以,于是增加了游客模式的页面(实际上就是判断是否已注册,没有就不让用某些功能)
- 登陆绑定就是简单的form表单提交并比对数据库的数据了,值得注意的是,表单组件里面的标签必须要有name属性才能提交成功
- 数据对比完之后,如果账号密码都正确,就把openid记录到数据库当中去,以后再登录的时候就可以直接查询数据库当中是否有其openid,如果有就可以直接进入主页面(上面的代码已经给出了判断)
之前的问题可能是没有使用云函数的问题,云开发省去了好多密钥之类的操作,云开发yyds!(大型项目还是老老实实code+key+……那我就不知道了)