小程序登录
小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系。
用户唯一标识 OpenID
- 同一个小程序,每个用户的openid是唯一的,并且不会变化
- 同一个用户对不同的小程序的openid是不相同的
- 可以通过wx.login方法获取用户的临时登录凭证code(code仅可使用一次)
- 将用户的临时登录凭证code回传到开发者服务器
- 开发者服务器进一步到微信服务器换取用户唯一标识openid
登录流程时序
登录流程时序图
- 小程序:小程序应用
- 开发者服务器:开发者自己搭建的业务服务器
- 微信接口服务:腾讯的接口服务器
代码逻辑
- 小程序端获取code,发送给开发者服务器
- 开发者服务器到微信接口服务器获取openid
- 开发者服务器保存openid与用户的对应关系,可以存在后台数据库中
- 开发者服务器返回用户的登录状态,可以自定义一个token返回
- 微信小程序与服务器交互时,需要携带token,以便开发者服务器识别用户身份。
本次实践任务
- 小程序通过wx.login方法获取code
- 将code传送给后台服务器
- 服务器通过code获取openid
- 服务器将自定义规则生成的toekn返回给小程序
- 小程序与后台进行业务交互时,携带token,以便后台能够识别该用户身份
准备工作
- 申请微信小程序(也可以使用测试号)
- 搭建后台服务器(可运行PHP、JAVA、GO、Python任一环境均可)
开始实践
1、小程序通过wx.login方法获取code
wx_login官方接口文档
示例代码如下:
wx.login({
success (res) {
if (res.code) {
console.log('登录成功!code值为:' + res.code)
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
将该部分代码加入到app.js中,替换9-14行代码片段,最终代码如下:
获取code值
每次登录code值是不一样的
2、将code传送给后台服务器
wx_request官方接口文档
示例代码如下:
wx.request({
url: 'test.php', //仅为示例,并非真实的接口地址
data: {
x: '',
y: ''
},
header: {
'content-type': 'application/json' // 默认值
},
success (res) {
console.log(res.data)
}
})
服务器需要开发一个api接口,用于接收code参数
接口URL:
- 例如:https://域名/index/api/get_code
请求方式:
- POST
参数:
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
code | 是 | string | 通过小程序获取的用户code,该值每次动态变化 ,无需保存 |
返回示例
{
"errcode": 0,
"token": "be6749ba99ccc20eaf5359c78cb9c3d63b0",
"uid": 3
}
返回参数说明:
参数名 | 类型 | 说明 |
---|---|---|
token | string | 后台根据一定规则生成的用户token,以后每次均需要带该参数 |
uid | int | 用户id,以后每次均需要带该参数,如果在token中已经包含了uid信息,则该参数可以省略,为了简单,我们保留该参数 |
3、服务器获取客户端传递的code
具体服务端代码实现过程,本专辑在后续的教程中会给大家介绍不同版本实现的方式。这里以thinkphp为例,介绍后端代码的实现逻辑。
服务器环境搭建步骤请关注公众号:《软件工程实践领航营》,历史消息中有详细的视频教程。
更详细的配置方式,也可以参考ThinkPHP5.0官方文档。
社区的小伙伴也写了学习笔记,大家也可以参考:https://blog.csdn.net/weixin_44735933/article/details/104895492
部署成功后的Thinkphp框架
在application/api/controller/目录下创建User.php文件,代码如下
image.png
设置站点伪静态,可以在URL中省略index.php
设置不校验合法域名
代码及结果
服务端代码完善
public function getcode()
{
//根据code 获取openid
$code = Request::instance()->post('code');
if(empty($code)){
return json([
'errcode' => 1001,
'msg' => '参数错误:code'
]);
}
return json([
'errcode' => 0,
'code' => $code
]);
}
小程序端代码完善
// 登录
wx.login({
success(res) {
if (res.code) {
console.log('登录成功!code值为:' + res.code)
wx.request({
//url: 'https://域名/index/api/get_code', //真实线上环境,域名需备案,加入到合法域名,并且是https协议
url: 'http://phpdemo.zhangqx.com/api/user/getcode0', //测试环境,可以在本地设置中忽略合法域名
data: {
code: res.code
},
method:'POST',
header: {
'content-type': 'application/x-www-form-urlencoded',
},
success(res) {
console.log(res.data)
if (res.data.errcode == 0) {
console.log('返回的 code:' + res.data.code);
console.log('返回的 token:' + res.data.token);
console.log('返回的 openid:' + res.data.openid);
}
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
服务端接受code,并返回给客户端
4、服务器获取openid并将自定义规则生成的toekn返回给小程序
服务端代码完善
public function getcode()
{
//根据code 获取openid
$code = Request::instance()->post('code');
if(empty($code)){
return json([
'errcode' => 1001,
'msg' => '参数错误:code'
]);
}
$appid = "wxdc0125b890004cf9";
$secret = "bf1f31b00bb2de865c192f428f8d0ece";
$curl = "https://api.weixin.qq.com/sns/jscode2session?appid=".$appid."&secret=".$secret."&js_code=".$code."&grant_type=authorization_code";
//echo $curl;
$res = $this -> get_request($curl);
$res = json_decode($res,true);
//var_dump($res);
if(isset($res['openid']) )
{
$openid =$res['openid'];
$token = $this->makeToken();
return json([
'errcode' => 0,
'openid' => $openid,
'token' => $token
]);
}
else{
return json([
'errcode' => 1002,
'openid' => "获取openid失败"
]);
}
}
private function get_request($url)
{
//初始化
$curl = curl_init();
//设置抓取的url
curl_setopt($curl, CURLOPT_URL, $url);
//设置头文件的信息作为数据流输出
curl_setopt($curl, CURLOPT_HEADER, false); //返回response头部信息
//设置获取的信息以文件流的形式返回,而不是直接输出。
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//执行命令
$data = curl_exec($curl);
//关闭URL请求
curl_close($curl);
//显示获得的数据
return $data;
}
private function makeToken()
{
$str = md5(uniqid(md5(microtime(true)), true)); //生成一个不会重复的字符串
$str = sha1($str); //加密
return $str;
}
小程序的id和秘钥可在小程序后台查询
小程序的id和秘钥
返回的token和openid