目录
前言
微信小程序登录是指用户通过微信账号在小程序中进行登录验证,获取授权状态后方能进行操作。以下是微信小程序登录的步骤:
- 用户打开小程序并点击登录按钮;
- 小程序向微信服务器发送登录请求,获取临时登录凭证code;
- 小程序将code发送给开发者服务器;
- 开发者服务器接收到code后,向微信服务器发送请求,获取用户的openid和session_key等信息;
- 开发者服务器将openid等信息保存在自己的数据库中,并将用户登录状态保存在session中;
- 小程序根据开发者服务器的响应,判断用户登录是否成功,如果成功则显示用户信息,否则提示登录失败。
需要注意的是,微信小程序的登录流程需要在微信开放平台注册小程序并获取AppID和AppSecret等信息后方能进行。同时,开发者服务器需要提供接收code并获取用户信息的接口。
一、为什么获取用户头像昵称失败?
更新时间:2022年11月9日
由于 PC/macOS 平台「头像昵称填写能力」存在兼容性问题,对于来自低于2.27.1版本的访问,小程序通过 wx.getUserProfile 接口将正常返回用户头像昵称,插件通过 wx.getUserInfo 接口将正常返回用户头像昵称。
更新时间:2022年9月28日
考虑到近期开发者对小程序用户头像昵称获取规则调整的相关反馈,平台将接口回收的截止时间由2022年10月25日延期至2022年11月8日24时。
调整背景
在小程序内,开发者可以通过 wx.login 接口直接获取用户的 openId 与 unionId 信息,实现微信身份登录,支持开发者在多个小程序或其它应用间匿名关联同一用户。
同时,为了满足部分小程序业务中需要创建用户的昵称与头像的诉求,平台提供了 wx.getUserProfile 接口,支持在用户授权的前提下,快速使用自己的微信昵称头像。
但实践中发现有部分小程序,在用户刚打开小程序时就要求收集用户的微信昵称头像,或者在支付前等不合理路径上要求授权。如果用户拒绝授权,则无法使用小程序或相关功能。在已经获取用户的 openId 与 unionId 信息情况下,用户的微信昵称与头像并不是用户使用小程序的必要条件。为减少此类不合理的强迫授权情况,作出如下调整。
调整说明
自 2022 年 10 月 25 日 24 时后(以下统称 “生效期” ),用户头像昵称获取规则将进行如下调整:
- 自生效期起,小程序 wx.getUserProfile 接口将被收回:生效期后发布的小程序新版本,通过 wx.getUserProfile 接口获取用户头像将统一返回默认灰色头像,昵称将统一返回 “微信用户”。生效期前发布的小程序版本不受影响,但如果要进行版本更新则需要进行适配。
- 自生效期起,插件通过 wx.getUserInfo 接口获取用户昵称头像将被收回:生效期后发布的插件新版本,通过 wx.getUserInfo 接口获取用户头像将统一返回默认灰色头像,昵称将统一返回 “微信用户”。生效期前发布的插件版本不受影响,但如果要进行版本更新则需要进行适配。通过 wx.login 与 wx.getUserInfo 接口获取 openId、unionId 能力不受影响。
- 「头像昵称填写能力」支持获取用户头像昵称:如业务需获取用户头像昵称,可以使用「头像昵称填写能力」(基础库 2.21.2 版本开始支持,覆盖iOS与安卓微信 8.0.16 以上版本),具体实践可见下方《最佳实践》。
- 小程序 wx.getUserProfile 与插件 wx.getUserInfo 接口兼容基础库 2.27.1 以下版本的头像昵称获取需求:对于来自低版本的基础库与微信客户端的访问,小程序通过 wx.getUserProfile 接口将正常返回用户头像昵称,插件通过 wx.getUserInfo 接口将正常返回用户头像昵称,开发者可继续使用以上能力做向下兼容。
二、解决方法
我们需要先获取用户的wxcode然后获取用户的openid
用以下方法获取用户的code,获取之后赋值,
wx.login({
success: (res) => {
this.setData({
wxCode: res.code,
});
然后将code发送到后端接口代码获取微信小程序的openid,获取用户openid这个过程一般在后端进行较安全。发送code
wx.request({
url: 'https://xxxxxxx/getVRopenid.php',//后端的接口文件所在地址
method:'GET',
data:{
wxCode:this.data.wxCode
},
header: {
'content-type': 'application/x-www-form-urlencoded' // 默认值
},
success:(res)=>{
app.globalData.userid=res.data.slice(8)
console.log("这是openid")
console.log(res.data.slice(8))
}
});
}
其中的url指的就是我们把接口文件放在服务器上的地址,一般都是根目录下,服务器搭建的相关内容请访文章:微信小程序开发环境准备(网站搭建准备)宝塔部署
下面是用PHP代码获取用户openid的过程
<?php
header('Content-Type: text/html;charset=utf-8');
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Headers: Content-Type,Content-Length,Accept-Encoding,X-Requested-with, Origin');
// 微信小程序的appId和appSecret
$appId = '这里填注册微信公众平台时获取的appid';
$appSecret = '这里填微信公众号注册时的密钥';
$wxCode=$_GET['wxCode'];//接受微信小程序传输过来的wxcode
// 访问获取openid的连接获取openid
$url = "https://api.weixin.qq.com/sns/jscode2session?&appid=$appId&secret=$appSecret&js_code=$wxCode&grant_type=authorization_code";
$info = curl_init();
curl_setopt($info,CURLOPT_RETURNTRANSFER,true);
curl_setopt($info,CURLOPT_HEADER,0);
curl_setopt($info,CURLOPT_NOBODY,0);
curl_setopt($info,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($info,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($info,CURLOPT_SSL_VERIFYHOST,false);
curl_setopt($info,CURLOPT_URL,$url);
$output = curl_exec($info);
curl_close($info);
$json = json_decode($output, true);
if ($json && isset($json['openid'])) {
$openid = $json['openid'];
echo 'openid: ' . $openid;
} else {
echo '获取openid失败';
}
?>
获取到后端的数据openid之后就可以将openid保存至数据库用于区分每一个用户,每个用户的openid都是独一无二的。
将openid保存至数据库一般就是用wx.request的方法带着需要存到数据库的参数,例如
wx.request是微信小程序中用于发起网络请求的API,具体用法如下,其中的key1和2就是需要传到数据库的参数:
wx.request({
url: '请求地址',
data: {
key1: value1,
key2: value2,
key3: value3
},
header: {
'content-type': 'application/json'
},
method: 'GET',
dataType: 'json',
responseType: 'text',
success: function(res) {
console.log(res.data)
},
fail: function(res) {
console.log('请求失败')
}
})
其中,url为请求地址,支持http、https、ftp等协议;data为请求参数,可以是字符串、对象或数组;header为请求头,可以设置请求的Content-Type;method为请求方法,支持GET、POST等;dataType为响应的数据类型,支持json、text等;responseType为响应的数据类型,支持text、arraybuffer等;success为请求成功的回调函数,fail为请求失败的回调函数。
后端代码为
<?php
header('Content-Type: text/html;charset=utf-8');
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Headers: Content-Type,Content-Length,Accept-Encoding,X-Requested-with, Origin');
$userid = $_POST['key1'];//微信小程序端传过来的参数赋值给userid
$nickName = $_POST['key2'];//微信小程序端传过来的参数赋值给nickName
$touxiang = $_POST['key3'];//微信小程序端传过来的参数赋值给touxiang
$servername = "localhost";
$username = "用户名";
$password = "数据库密码";
$dbname = "数据库名";
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
// 检查用户是否已存在
$sql1 = "SELECT * FROM user WHERE userid = '$userid'";
$result = $conn->query($sql1);
if ($result->num_rows > 0) {
// 用户已存在,输出消息
echo "用户已存在";
} else {
// 用户不存在,插入新数据到数据库
$sql = "INSERT INTO user (userid,nickName,touxiang) VALUES ('$userid','$nickName','$touxiang');";//将对应的数据存到对应的数据下,前面的userid等在些代表的是数据库中的字段,而后面的带$符的是接受微信小程序端传输过来的数据之后赋值给这几个
$res = $conn->query($sql);
echo json_encode(array('success'=>$res,'msg'=>$res?'数据写入成功':'数据写入失败','sql'=>$sql));
}
$conn->close();
?>
这样就可以把用户信息存到数据库中
补充
版本更新之后如何获取用户头像和昵称
微信小程序的chooseAvatar接口可以实现用户选择头像的功能,具体使用方法如下:
-
在需要选择头像的页面中,引入wx.chooseImage方法。
-
使用wx.chooseImage方法,在success回调函数中获取到用户选择的头像文件地址。
-
使用wx.uploadFile方法,将头像文件上传到服务器并返回url地址。
-
在页面上显示选择的头像。
示例代码如下:
wx.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: function (res) {
var tempFilePaths = res.tempFilePaths
wx.uploadFile({
url: 'your server url',
filePath: tempFilePaths[0],
name: 'filename',
success: function(res){
// 上传成功,返回url地址
var url = res.data
// 在页面上显示头像
console.log('头像url:', url)
},
fail: function(res){
console.log('上传失败:', res)
}
})
}
})
注意事项:
-
count参数表示可以选择图片的数量,此处只允许选择1张。
-
sizeType参数表示压缩图片,保证上传速度。
-
sourceType参数表示可以从相册或相机选择图片。
-
uploadFile方法需要传入服务器的url地址、选择的文件路径、参数名等信息。
-
上传成功后,返回的res.data即为上传的url地址,可以在页面上显示。
也可以使用以下方法:
wxml
<view data-weui-theme="{{theme}}">
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
<image class="avatar" src="{{avatarUrl}}"></image>
</button>
<mp-form>
<mp-cells>
<mp-cell title="昵称">
<input bindinput="nickname" class="weui-input" placeholder="请选择头像并输入昵称" placeholder-style="color:#000000"/>
</mp-cell>
</mp-cells>
</mp-form>
</view>
<button bind:tap="login" type="primary">登录
</button>
这是我的对应的js文件
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
const app = getApp()
Page({
data: {
avatarUrl: defaultAvatarUrl,
theme: wx.getSystemInfoSync().theme,
nologin: false,
wxCode: "", // 获取到的code
touxiang:''
},
nickname(event){
app.globalData.nickName=event.detail.value
console.log(app.globalData.nickName)
},
onLoad(options) {
wx.onThemeChange((result) => {
this.setData({
theme: result.theme
})
});
},
onChooseAvatar(e) {
wx.login({
success: (res) => {
this.setData({
wxCode: res.code,
});
wx.request({
url: 'https://xxxxxxx/getVRopenid.php',//填写服务器接口代码地址这是获取用户openid的代码
method:'GET',
data:{
wxCode:this.data.wxCode
},
header: {
'content-type': 'application/x-www-form-urlencoded' // 默认值
},
success:(res)=>{
app.globalData.userid=res.data.slice(8)//截取字符串,我的openid多出来几个字符,所以截取字符串
console.log("这是openid")
console.log(res.data.slice(8))
}
});
}
});
const { avatarUrl } = e.detail
this.setData({
avatarUrl,
})
app.globalData.touxiang=avatarUrl;
},
login() {
if((app.globalData.touxiang&&app.globalData.nickName&&app.globalData.userid)){
const userid = app.globalData.userid;
wx.request({
url: "https://xxxxxxxxxxx/post.php",//填写服务器接口代码地址这是向数据库插入用户信息的代码
method: "POST",
data: {
userid: userid,
nickName: app.globalData.nickName,
touxiang: app.globalData.touxiang,
},
header: {
'content-type': 'application/x-www-form-urlencoded' // 默认值
},
success: (res) => {
console.log(app.globalData.nickName)
this.setData({
nologin:true
})
if(this.data.nologin){
console.log(res.data)
wx.reLaunch({
url: '/pages/myself/myself'//这是用户登录之后跳转到个人中心页面,也可以自己设置跳转页面
});}
},
fail: function (res) {
console.log('提交失败');
}
})
}else{//用户信息不完善时点击登录跳出错误的信息
wx.showToast({
title: '请完善信息', //提示的内容
duration: 2000, //持续的时间
icon: 'error', //图标有success、error、loading、none四种
mask: true //显示透明蒙层 防止触摸穿透
})
}
}
})