前言:微信文档写的零零散散的,网上搜的教程,23年的教程还在教22年改版之前的东西,导致踩坑无数,所以自己写一下文档记录一下,帮助后来者,记录于2024.11.14
一.获取用户头像和昵称
首先阅读微信小程序官方文档,wx.getUserInfo接口开放接口 / 用户信息 / wx.getUserInfo (qq.com)
发现自2022年之后,开发的版本逐渐对用户信息接口更改,wx.getUserInfo接口已经基本弃用,之前老版本还能够使用,但是新版小程序调用此接口只能获取到一堆默认信息如下
小程序登录、用户信息相关接口调整说明 | 微信开放社区 (qq.com)
所以要实现获取用户头像,不能像之前一样一键获取了,有的文档说会调起一个授权弹窗,然后用户手动授权之后就可以获取,亲测这个方法已经过时,即下图这个方法并不会弹出个人信息确认弹窗
目前唯一可行的方法就是:头像昵称填写能力
开放能力 / 用户信息 / 获取头像昵称 (qq.com)
需要将 button 组件 open-type
的值设置为 chooseAvatar
,当用户选择需要使用的头像之后,可以通过 bindchooseavatar
事件回调获取到头像信息的临时路径。
需要将 input 组件 type
的值设置为 nickname
,当用户在此input进行输入时,键盘上方会展示微信昵称。
其中有两个需要注意的点:
1.选择的微信头像是暂存到本地的路径,随时可能会失效,或者出现307重定向等一系列bug,所以要把头像上传的自己本地的服务器,或者本地的接口保存,就是把onChooseAvatar方法修改成如下
onChooseAvatar: function(e) {
const {
avatarUrl
} = e.detail
let _this = this
wx.uploadFile({
url: '', // 你自己本地上传图片的 完整 路径
filePath: avatarUrl,
name: 'file', // 文件对应的 key,开发者在服务端可以通过这个 key 获取文件的二进制内容
success(res) {
console.log("data===>",res.data)
_this.setData({
avatarUrl:'' // 你自己的完整图片路径
})
}
})
},
2.微信昵称选择的时候,输入框有值,并且绑定了v-model,并不会被监听到,即使修改了,值也还是空的,必须要用户手动再修改才会被v-model发现修改,这是一个bug吧,所以要手动用watch监听一下输入框绑定的值
获取头像昵称示例代码如下:
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
<image class="avatar" src="{{avatarUrl}}"></image>
</button>
<input type="nickname" class="weui-input" placeholder="请输入昵称"/>
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
export default{
data(){
avatarUrl: defaultAvatarUrl, // 可以自行修改
},
methods:{
}
}
onChooseAvatar(e) { // 将这个方法修改为上面那个,注意变量名更改
const { avatarUrl } = e.detail
this.setData({
avatarUrl,
})
}
})
二.微信授权登录
主要用到的接口就是wx.login接口,其功能如下:
调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台账号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台账号)及本次登录的会话密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成。
很抽象,通俗来讲,就是调用wx.login接口,微信会给你返回一个code,通过这个code传给后端,后端会通过系列操作(这个系列操作后面会讲)返回给你一个openid,unionid和session_key,作用我都会一一介绍。然后上文说的解密通讯是交给后端完成的。
openid作用是用户在本小程序的唯一作用标识。
unionid是多个小程序之间,同一用户,不用重新授权即可直接登录的标识,此unionid需要注册微信开放平台认证才可获得,如果只是开发一个小程序则不需要这个id。
session_key:五分钟一次刷新,用来判断登录是否过期。
首先我们来阅读官方文档开放接口 / 登录 / wx.login (qq.com)
下图是从别的博客借鉴来的,三列,第一列是前端要做的,第二列是后端要做的
首先,在登录界面的onLoad函数中调用wx.login
onLoad: function(options) {
let that = this;
wx.login({
success: res => {
that.code = res.code
}
})
},
把这个code保存下来。然后通过自己的wxLogin把这个code传给后端,后端阅读这个文档
小程序登录 / 小程序登录 (qq.com)
调用微信的服务
GET https://api.weixin.qq.com/sns/jscode2session
后端直接配置下面四个参数然后调用
appid和secret在微信小程序的平台内可以查看到,js_code就是前端传入的code,下一个参数直接填写authorization_code即可、然后微信服务器会返回openid等参数,然后把这个openid返回给前端,同时在这个login接口里面注册用户保存到数据库,把userId和openid一起返回给前端,到此登录流程就结束了。
三.获取用户手机号
阅读官方文档开放能力 / 用户信息 / 手机号快速验证组件 (qq.com)
<button open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">微信授权登录</button>
注意,现在手机号快速验证需要收费了,如果你是个人appid,则需要完成微信小程序认证,300一年,如果不想认证还想用这个功能,就要用测试号,把appid和secret都换成测试号的。
而且现在这个获取用户手机号,不用wx.login也可以登录
使用方法
步骤1:需要将 button 组件 open-type
的值设置为 getPhoneNumber
,当用户点击并同意之后,通过 bindgetphonenumber
事件获取回调信息;
步骤2:将 bindgetphonenumber
事件回调中的动态令牌code
传到开发者后台,并在开发者后台调用微信后台提供的 phonenumber.getPhoneNumber 接口,消费code
来换取用户手机号。每个code
有效期为5分钟,且只能消费一次。
注:getPhoneNumber
返回的 code
与 wx.login
返回的 code
作用是不一样的,不能混用。这句话很重要!!在和授权登录一起写的时候很容易弄混。
我是直接全都在前端调用了,效果如下
!!!今天上线体验版的时候发现,https://api.weixin.qq.com这个域名不能配置为合法域名,微信直接把这个禁用了,即这一段代码全都必须只能放在后端运行,即后端写一个接口,接受code参数,然后把下面代码中的e.detail.code这个参数传给后端,下面的一系列post微信服务的接口都由后端来完成,直接返回电话号码即可、
文档:获取手机号 | 微信开放文档
后端操作:
先调用https://api.weixin.qq.com/cgi-bin/stable_token,post方法,传参grant_type: 'client_credential', appid: config.appid, secret: config.secret
获取到token,这个token是获取手机号的token,不是登录的token
然后调用url: `https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=` + token,post方法,传参code,返回的数据就是包含手机号的数据
getPhoneNumber(e) {
console.log("e=>", e) // 这里会返回encryptedData和iv,用来加密和解密
if (e.detail.errMsg === 'getPhoneNumber:ok') {
// this.encryptedData = e.detail.encryptedData
// this.iv = e.detail.iv
const code = e.detail.code;
let promise = new Promise((resolve, reject)=> {
var params = {
url: '/login',
data: {
principal: this.code,
},
callBack: res => {
http.loginSuccess(res) // 这是我自己外部文件保存登录token等信息
}
}
http.request(params)
resolve();
});
promise.then((res)=>{
uni.request({
url: `https://api.weixin.qq.com/cgi-bin/stable_token`,
method: "POST",
data: {
grant_type: 'client_credential',
appid: config.appid,
secret: config.secret
},
success: res => {
// 此token和code不是login的token和code,这一步可以放到后端写
this.getPhone(res.data.access_token, code);
},
fail: err => {
console.error("调用失败=>", err);
}
});
})
} else {
console.error('用户未授权手机号');
uni.showToast({
title: '用户未授权手机号',
icon: 'none'
});
}
},
getPhone(token, code) {
// 获取手机号
uni.request({
url: `https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=` + token,
method: "POST",
data: {
code: code
},
success: res => {
console.log("获取到的用户手机号全部信息:", res);
// 获取到手机号
this.phoneNumber = res.data.phone_info.purePhoneNumber;
console.log("流程结束!!")
},
fail: err => {
console.error("获取手机号失败", err);
uni.showToast({
title: '获取手机号失败',
icon: 'none'
});
}
});
},
手动删减的,有的地方花括号可能会有报错,请见谅,但大体流程就是上面那样,最后res.data.phone_info.purePhoneNumber就是最终的用户手机号。
获取手机号和微信授权登录可以写到同一个按钮里面,具体逻辑可以自己操作