当前位置:网站首页>实战剖析: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具体逻辑思维图:

边栏推荐
- Weekly recommended short video: talk about "meta universe" with a serious attitude
- 2022-06-23: given a nonnegative array, select any number to make the maximum cumulative sum a multiple of 7, and return the maximum cumulative sum. N is larger, to the 5th power of 10. From meituan. 3
- 牛客网 字符串变形
- 每周推荐短视频:计算的终极形态是“元宇宙”?
- 从618看京东即时零售的野心
- On the routing tree of gin
- [redis realize Secondary killing Business ①] Overview of Secondary killing Process | Basic Business Realization
- Some common pitfalls in getting started with jupyter:
- Thinkphp5清除runtime下的cache缓存,temp缓存,log缓存
- Microblog writing - flow chart - sequence chart - Gantt chart - Mermaid flow chart - good results
猜你喜欢

How to configure environment variables and distinguish environment packaging for multi terminal project of uniapp development
![[e325: attention] VIM editing error](/img/58/1207dec27b3df7dde19d03e9195a53.png)
[e325: attention] VIM editing error

cookie加密 4 rpc方法确定cookie加密

【Redis實現秒殺業務①】秒殺流程概述|基本業務實現

Cdga | how can we do well in data governance?

12、 Demonstration of all function realization effects

Ebanb B1 Bracelet brush firmware abnormal interrupt handling
![[Niuke] convert string to integer](/img/56/3e491b3d0eea0d89a04d0b871501d7.png)
[Niuke] convert string to integer

Linux MySQL installation
![[noi Simulation Competition] send (tree DP)](/img/5b/3beb9f5fdad00b6d5dc789e88c6e98.png)
[noi Simulation Competition] send (tree DP)
随机推荐
支持向量机(SVC,NuSVC,LinearSVC)
活动报名|Apache Pulsar x KubeSphere 在线 Meetup 火热报名中
cookie加密 4 rpc方法确定cookie加密
Niuke network realizes simple calculator function
Cmake命令之target_compile_options
正则匹配手机号
Ordinary people have no education background. Can they earn more than 10000 yuan a month by Self-taught programming?
Pytoch read data set (two modes: typical data set and user-defined data set)
浮点数表示法(总结自CS61C和CMU CSAPP)
解决:jmeter5.5在win11下界面上的字特别小
Unable to change the virtual machine power status and report an error solution
【Redis实现秒杀业务①】秒杀流程概述|基本业务实现
I heard that you are still spending money to buy ppt templates from the Internet?
Thinkphp5清除runtime下的cache缓存,temp缓存,log缓存
软件系统依赖关系分析
Project deployment related
[redis implements seckill business ①] seckill process overview | basic business implementation
[Niuke] convert string to integer
Inspiration from reading CVPR 2022 target detection paper
当程序员被问会不会修电脑时… | 每日趣闻