当前位置:网站首页>实战剖析:app扫码登陆实现原理(app+网页端详细逻辑)附源码
实战剖析:app扫码登陆实现原理(app+网页端详细逻辑)附源码
2022-06-24 08:08:00 【BigChen_up】
记录一下最近在做的一个app扫码登陆的功能。
文章最底下附app以及网页端具体逻辑思维图
具体思路如下:
1.后台生成一个唯一值,附加到二维码上,返回给前端页面,这个唯一值保存到数据库里一份,用来后续的比对。(生成二维码的方法有很多种,网上很多这里就不过多的介绍了,后边有代码)。
2.前端AJAX轮询请求二维码的状态,判断是否已扫、确认登陆、取消登陆、超时等信息。
3.APP扫码,用户使用APP扫码后向网页端接口传递一个状态字段表示已扫,前端ajax轮询判断状态是已扫就隐藏掉二维码。用户点击确认登陆向网页端接口传递确认登陆状态,以及用户的唯一标识,前端ajax判断是确认登陆,获取到用户唯一标识后查询数据库存储对应session,跳转到对应页面。
/** * 生成二维码 * @param string $url 二维码中的内容,加http://这样扫码可以直接跳转url * @param string $message 二维码下方注释 * @param string $logo 二维码中间logo图片 * @param int $logo_w 图片大小 * @param int $size 二维码大小 * @return string 二维码 */
function qrcode($url, $message = '', $logo = '', $logo_w = 50, $size = 300) {
$errorCorrectionLevel = 'L'; //容错级别
$matrixPointSize = 3; //生成图片大小
//生成二维码图片
QrCode::png($url, '../qr/qrcode.png', $errorCorrectionLevel, $matrixPointSize, 2);
$logo = 'static/img/logo.png'; //准备好的logo图片
$QR = '../qr/qrcode.png'; //已经生成的原始二维码图
if ($logo !== FALSE) {
$QR = imagecreatefromstring(file_get_contents($QR));
$logo = imagecreatefromstring(file_get_contents($logo));
if (imageistruecolor($logo)) imagetruecolortopalette($logo, false, 65535);
$QR_width = imagesx($QR); //二维码图片宽度
$QR_height = imagesy($QR); //二维码图片高度
$logo_width = imagesx($logo); //logo图片宽度
$logo_height = imagesy($logo); //logo图片高度
$logo_qr_width = $QR_width / 6;
$scale = $logo_width / $logo_qr_width;
$logo_qr_height = $logo_height / $scale;
$from_width = ($QR_width - $logo_qr_width) / 2;
//重新组合图片并调整大小
imagecopyresampled($QR, $logo, $from_width, $from_width, 0, 0, $logo_qr_width,
$logo_qr_height, $logo_width, $logo_height);
}
//输出图片
imagepng($QR, '../qr/appdownload.png');
//base64二维码
$qrcode = file_get_contents('../qr/appdownload.png');
$qr_img = "data:image/jpg;base64," . base64_encode($qrcode);
return $qr_img;
}
生成二维码接口
/** * Notes: 生成二维码方法 */
public function sweepCodeOp() {
if (request()->isGet() && request()->isAjax()) {
// 创建token
$token = get_token();
$check_token = check_token();
// 生成二维码
// 这里边的地址暂时是模拟地址
$qr = qrcode('ceshi.cn/user/login?token=' . $token . '&check_token=' . $check_token);
$data = [
'token' => $token,
'addtime' => time(),
'check_token' => $check_token,
];
// 新增二维码表
$res = model('qrcode')->allowField(true)->validate('qrcode.add')->save($data);
if ($res === false) {
return false;
}
return return_msg(1, '生成验证码成功', $qr, $token);
}
return $this->fetch();
}
前端点击获取二维码请求后台这个生成二维码的接口,判断code等于1标识获取二维码成功,然后开始定时轮询二维码状态的接口,具体ajax轮询如下:
var flag = true;
var timer;
var a = 1;
function qrcode() {
if (flag == true) {
// 防止用户频繁点击
flag = false;
clearInterval(timer);
$.ajax({
type:"GET",
url:"sweepCode",
data:{
},
success:function (adata) {
var data = JSON.parse(adata);
// console.log(data.token);
// var token = data.token;
if (data.code == 1) {
// 1 表示二维码生成成功
$("#qr").attr('src',data.data);
timer = setInterval(function () {
// console.log(a);
$.ajax({
type:"POST",
url:"getStatus",
data:{
token:data.token},
success:function (res) {
var ares = JSON.parse(res);
// console.log('T--'+data.token);
console.log(ares);
switch (ares.code) {
case 1201: // 1201 表示二维码过期
console.log(ares.msg);
$("#qr").attr('src','');
clearInterval(timer);
break;
case 1205: // 表示用户扫描了二维码
$("#qr").attr('src','');
$("#success").css('display','block');
break;
case 1207: // 1207 表示用户扫描过但点击取消登录
$("#success").css('display','none');
$("#rem").css('display','block');
clearInterval(timer);
break;
case 1202: // 1202 表示账号不存在
break;
case 1203 : // 1203 表示账号未绑定成功
break;
case 200: // 200 表示登录成功 里边要写跳转
$("#success").text(ares.username);
clearInterval(timer);
alert(ares.msg);
// location.href="/index/index/index";
break;
case 400: // 表示参数错误
clearInterval(timer);
break;
case 1211: // 数据异常
break;
}
}
});
},2000);
} else {
console.log('未知错误!');
}
}
});
setTimeout(function () {
// 设置点击频率
flag = true;
},2000);
a++;
} else {
console.log('点击过于频繁');
a -- ;
}
}
查询二维码状态的接口如下: (因为是实战项目用到的功能,所以判断以及遇到的各种情况的判断比较复杂,如果自己练习使用可以简化着写)
/** * Notes: 轮询查询二维码状态 * @return string */
public function getStatusOp() {
if (request()->isAjax() && request()->isPost()) {
$token = preg_replace('/\s/', '', input('token'));
// 实例化二维码表
$qrcode = model('qrcode');
// 删除一些未轮询过期的二维码
$del = $qrcode->field('addtime,numid')->select();
foreach ($del as $v) {
if (time() - $v['addtime'] > 400) {
$qrcode->where(['numid' => $v['numid']])->delete();
}
}
// 实例化用户表
$user = model('user');
// 查二维码表
$result = $qrcode->where(['token' => $token])->find();
if (!empty($result)) {
if (time() - $result['addtime'] > 300) {
// 请求超时
$qrcode->where(['token' => $token])->delete();
return return_msg(1201, '二维码过期请刷新');
}
switch ($result['status']) {
case 0: // 表示未扫描
return return_msg(1200, '二维码未扫描,请扫描二维码');
break;
case 1: // 表示已扫描
if ($result['qrstatus'] == 7) {
// 二维码状态 7 为取消登录
$qrcode->where(['token' => $token])->delete(); // 删除二维码
return return_msg(1207, '二维码已取消授权');
} elseif ($result['qrstatus'] == 9) {
// 二维码状态 9 为确认登录
if (!empty($result['uid'])) {
// 查用户表
$res_user = $user->where(['numid' => $result['uid']])->field('username,numid')->find();
if ($res_user !== false) {
// 给session赋值
session('username', $res_user['username']);
session('uid', $res_user['numid']);
// 删除二维码
$qrcode->where(['token' => $token])->delete();
return return_msg(200, '登录成功', session('username')); // 登录成功要跳转
} else {
return return_msg(1202, '账号不存在');
}
} else {
// 删除二维码
$qrcode->where(['token' => $token])->delete();
return return_msg(1203, '账号未绑定');
}
} else {
return return_msg(1205, '请手机客户端确认登录');
}
break;
default:
return return_msg(1211, '数据异常!');
break;
}
} else {
return return_msg(400, '参数错误!');
}
}
}
APP传递参数的接口如下:
/** * Notes: app 传递过来参数 * @return string */
public function getAppOp() {
if (request()->isPost()) {
$arr = [
'token' => preg_replace('/\s/', '', input('token')),
'check_token' => preg_replace('/\s/', '', input('check_token')),
'type' => intval(input('type')), // 1 扫过码 7 取消登录 9 确认登录
'uid' => intval(input('uid')),
];
// 实例二维码表
$qrcode = model('qrcode');
$token = $arr['token'];
$check_token = $arr['check_token'];
// 判断传递过来的token是否正确
$addtime = $qrcode->where(['token' => $token, 'check_token' => $check_token])->value('addtime');
if (!empty($addtime)) {
// token正确
if ((time() - $addtime) < 300) {
// 且 没有超时
switch ($arr['type']) {
case 1: // 表示已扫
$qrcode->isUpdate(true, ['token' => $token, 'check_token' => $check_token])->save(['status' => 1]);
return return_msg(1300, '扫码成功!');
break;
case 7: // 更新qrstatus 表示取消登录
$qrcode->isUpdate(true, ['token' => $token, 'check_token' => $check_token])->save(['qrstatus' => 7]);
return return_msg(1301, '取消登录!');
break;
case 9: // 表示确认登录
if (!empty($arr['uid'])) {
$qrcode->isUpdate(true, ['token' => $token, 'check_token' => $check_token])->save(['qrstatus' => 9, 'uid' => $arr['uid']]);
return return_msg(1302, '登录成功!');
} else {
return return_msg(1303, '账号绑定失败!');
}
break;
default:
return return_msg(1401, '数据异常!');
break;
}
} else {
return return_msg(1402, '超时!');
}
} else {
return return_msg(1403, '验证失败!');
}
}
}
网页端具体逻辑思维图:

APP具体逻辑思维图:

边栏推荐
- PHP封装一个文件上传类(支持单文件多文件上传)
- Support vector machine (SVC, nusvc, linearsvc)
- php单例模式详解
- Mba-day25 best value problem - application problem
- [noi simulation] pendulum (linear algebra, Du Jiao sieve)
- Depens:*** but it is not going to be installed
- 【ES6闯关】Promise堪比原生的自定义封装(万字)
- Redis实现全局唯一ID
- 最新Windows下Go语言开发环境搭建+GoLand配置
- [e325: attention] VIM editing error
猜你喜欢

Redis实现全局唯一ID
![[Niuke] convert string to integer](/img/56/3e491b3d0eea0d89a04d0b871501d7.png)
[Niuke] convert string to integer

The ambition of JD instant retailing from 618
![The printed object is [object object]. Solution](/img/fc/9199e26b827a1c6304fcd250f2301e.png)
The printed object is [object object]. Solution

From the Huawei weautomate digital robot forum, we can see the "new wisdom of government affairs" in the field of government and enterprises

深入了解 border

【Redis实现秒杀业务①】秒杀流程概述|基本业务实现

当程序员被问会不会修电脑时… | 每日趣闻

I heard that you are still spending money to buy ppt templates from the Internet?

Support vector machine (SVC, nusvc, linearsvc)
随机推荐
Huawei Router: GRE Technology
Every (), map (), forearch () methods. There are objects in the array
The list of open source summer winners has been publicized, and the field of basic software has become a hot application this year
[noi Simulation Competition] send (tree DP)
Zero foundation self-study SQL course | having clause
金仓KFS replicator安装(Oracle-KES)
Niuke network realizes simple calculator function
【Redis實現秒殺業務①】秒殺流程概述|基本業務實現
Kaformer personal notes
Numpy NP in numpy c_ And np r_ Explain in detail
Target detection series fast r-cnn
Cmake命令之target_compile_options
Implementation process of tcpdump packet capturing
【LeetCode】387. First unique character in string
198. 打家劫舍
Time series data augmentation for deep learning: paper reading of a survey
Transplantation of xuantie e906 -- fanwai 0: Construction of xuantie c906 simulation environment
零基础自学SQL课程 | 子查询
PhpStrom代码格式化设置
PM2 deploy nuxt3 JS project