概述
记录一下最近在做的一个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具体逻辑思维图:
最后
以上就是善良人生为你收集整理的实战剖析:app扫码登陆实现原理(app+网页端详细逻辑)附源码的全部内容,希望文章能够帮你解决实战剖析:app扫码登陆实现原理(app+网页端详细逻辑)附源码所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复