基础术语
1. code: 调用wx.login后返回的临时登录凭证,可请求微信服务器换取openId和session_key
2. openId:用户唯一标识,同一用户在不同的应用中不一致
3. session_key:对用户数据进行加密签名的密钥
4. appId:小程序唯一标识,申请小程序成功后获得分配
5. unionId:用户在开放平台的唯一标识符,同一用户在同一账号下的所有应用中一致
UnionID 机制说明
如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。
UnionID获取途径
UnionID
获取途径:绑定了开发者帐号的小程序,可以通过下面的途径获取 UnionID
。
-
调用接口
wx.getUserInfo
,从解密数据中获取UnionID
。注意本接口需要用户授权,请开发者妥善处理用户拒绝授权后的情况。 -
如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号。开发者可以直接通过
wx.login
+code2Session
获取到该用户UnionID
,无须用户再次授权。 -
如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用。开发者也可以直接通过
wx.login
+code2Session
获取到该用户UnionID
,无须用户再次授权。 -
用户在小程序(暂不支持小游戏)中支付完成后,开发者可以直接通过
getPaidUnionId
接口获取该用户的UnionID
,无需用户授权。注意:本接口仅在用户支付完成后的5分钟内有效,请开发者妥善处理。 -
小程序端调用云函数时,如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号,可在云函数中通过
cloud.getWXContext
获取UnionID
。 -
小程序端调用云函数时,如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用,也可在云函数中通过
cloud.getWXContext
获取UnionID
。
小程序登录流程示意图
1. 通过wx.login() 获取code
2. 将code发送给后端,后端请求微信服务器code2Session接口换取openId和sessionKey
3. 将openId与唯一登录态绑定并把登录态返回给用户
需要授权的信息
部分接口需要经过用户授权同意才能调用,如用户信息、地理位置、地址等等,需要注意的是,如果用户已经拒绝了授权,就不会再出现授权弹窗,此时应该引导用户前往设置界面打开授权,开发者可以调用 wx.openSetting
打开设置界面,引导用户开启授权。
提前发起授权
除了 userInfo
,其他的授权信息都可以使用 wx.authorize
提前发起授权,而 userInfo
只能通过 button
触发。
// 点击后将出发弹窗,点击允许或拒绝将调用回调
<button open-type="getUserInfo" bindgetuserinfo="getUserInfo">
getUserInfo(e) {
// 用户拒绝授权
if (e.detail.errMsg == 'getUserInfo:fail auth deny'){
this.showError('您还没有授权微信登录');
} else {
// 获取用户信息成功
this.weixinLoginNew();
}
}
e.detail
数据结构说明(跳过吧)
- encryptedData: 加密后的用户敏感信息,如openId和unionId
- iv:加密算法的初始向量,后端通过iv、encryptedData及解密算法进行解密获得openId
- signature:数据签名,signature = sha1( rawData + session_key ),开发者将 signature、rawData 发送到开发者服务器进行校验。服务器利用用户对应的 session_key 使用相同的算法计算出签名 signature2 ,比对 signature 与 signature2 即可校验数据的完整性。
- userInfo:用户非敏感信息,包含头像、昵称、性别等
需要授权的信息列表
scope | 对应接口 | 描述 |
---|---|---|
scope.userInfo | wx.getUserInfo | 用户信息 |
scope.userLocation | wx.getLocation, wx.chooseLocation | 地理位置 |
scope.address | wx.chooseAddress | 通讯地址 |
scope.invoiceTitle | wx.chooseInvoiceTitle | 发票抬头 |
scope.invoice | wx.chooseInvoice | 获取发票 |
scope.werun | wx.getWeRunData | 微信运动步数 |
scope.record | wx.startRecord | 录音功能 |
scope.writePhotosAlbum | wx.saveImageToPhotosAlbum, wx.saveVideoToPhotosAlbum | 保存到相册 |
scope.camera | <camera /> 组件 |
摄像头 |
获取手机号
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
Page({
getPhoneNumber(e) {
// 揭秘后JSON结构:{phoneNumber(有区号), purePhoneNumber, countryCode }
console.log(e.detail.encryptedData)
}
})
案例(封装了一个微信登录组件)
1. 查看用户设置信息验证是否授权过
ready() {
wx.getSetting({
success: (res) => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 wx.getUserInfo 获取头像昵称
this.setData({ isAuthorization : true});
}
}
});
}
2. 页面结构
如果已经授权过,则可以直接调用 wx.getUserInfo
无需按钮授权,slot
中可以放置任何元素,用以描述登录按钮。
<view class="login-wrap" catchtap="weixinLogin">
<slot></slot>
<button wx:if="{{ !isAuthorization }}" open-type="getUserInfo" bindgetuserinfo="getUserInfo" class="wx-btn" size="min">
</button>
</view>
// 数据
data: {
isAuthorization: false, // 是否已经验证过
canIUse: wx.canIUse('button.open-type.getUserInfo'),
},
/* 样式 */
<style lang="scss">
.login-wrap {
position: relative;
}
.wx-btn {
width: 100%;
height: 100%;
position: absolute;
left: 0rpx;
top: 0rpx;
z-index: 100;
border-radius:0rpx;
background:none;
margin:0rpx;
padding:0rpx;
}
.wx-btn:after {
border: none;
}
</style>
3.处理点击行为
如果用户已经授权,则会触发 weixinLogin
事件。
weixinLogin (e) {
if (!this.data.isAuthorization) return;
// 通过 wx.login() 完成微信登录
// 通过 wx.getUserInfo() 获取用户信息
},
如果用户未授权过,则会触发 getUserInfo
事件。
// 微信登录按钮触发getUserInfo
getUserInfo(e) {
if (!this.data.canIUse){
this.showError('请升级微信到最新版本');
return;
}
if (e.detail.errMsg == 'getUserInfo:fail auth deny'){
this.showError('您还没有授权微信登录');
} else{
wx.showLoading({ title: 'loading', mask: true });
// 通过 wx.login() 完成微信登录
// 通过 wx.getUserInfo() 获取用户信息
}
}