前幾天買阿里云服務器的時候,被掃碼登陸給吸引到了。然后就一直在琢磨自己的實現方式。也許是巧合吧,昨晚竟然在夢中找到了一個自認為還不錯的實現思路。但是已經凌晨了,為了防止忘記,趕緊寫了個小紙條放在床邊。于是今天上午就著手編碼做了個雛形。
作此文,以記之。
原理
感覺還是應該先進行聲明一下。
純屬個人拙見,如果有些許不當,還望海涵。
按照我掃碼登陸的親身經歷,可以分為下面幾個階段。
打開網頁
拿阿里云來說,打開首頁點擊登錄按鈕之后,就會跳轉到下面的這個網頁,讓我們使用阿里云手機客戶端 掃碼。
掃碼階段
其實我們可能會很疑惑,為什么一掃碼, 人家就能知道咱掃過了呢?而且就這么真的登陸成功了?
其實如果讓我自己來做的話,關鍵就在于這個阿里云手機客戶端。眾所周知,二維碼只是個用于傳遞數據的工具,它本身并不能幫助我們確認是否被掃碼,被誰掃了。
但是關鍵就在于這個數據。其實這個數據至關重要,因為借助此數據,手機客戶端才能“定位”(這個詞不是特別貼切,看完后面的相信就可以明白了。)
驗證階段
然后手機客戶端,將客戶端上已經登錄的您的賬號,加上這個數據。
-
如果在時效內確認,則會登陸成功。
掃碼成功 -
如果時效內未進行驗證,則二維碼失效。
二維碼失效
如此將需要的數據進行打包,然后向服務器發送一個請求,然后服務器通過這個數據 定位到數據庫中相關的登錄表上,然后添加登陸的用戶的用戶名,確認登陸。然后登陸標記記為已登錄, 狀態。
好了,大致的整個流程就是這樣了,是不是很容易也可以理解呢。
準備
“工欲善其事,必先利其器”,所以咱們還是先著手搭建一個好用的環境吧。
搭建環境
可能每個人使用的軟件版本會有所不同,但是基本上都是可以正常工作的,如果您正確安裝了的話。 下面羅列一下我自己的環境。
服務器環境
- PHP5.2.8
- Apache2.2
- MySQL5.7
第三方依賴
另外,本次試驗要完成的是掃碼登陸,所以必不可少的要生成二維碼。在PHP中生成二維碼的方式有很多,比較常用的是:
借助google api.可以參照: http://www.jb51.net/article/37775.htm
-
借助PHP QRCode 庫。
然后為了更加方便的進行HTML元素的操作,就把JQuery也拿過來好了。
不過這不是必須需要的,如果不想用,可以用原生的JavaScript來實現。
我用的是
jquery-2.2.4.min.js
后端
我感覺上面原理熟悉了之后,后臺設計就應該很簡單了。先來看看目錄結構吧(比較散亂,吸取教訓哈)。
數據庫
因為這次試驗主要是為了實現掃碼登陸,所以就直接設計一個登錄表好了,雖然實際中肯定不是這樣的。也比這要復雜的多。
id就作為上面講述的那個特殊的數據。
而創建時間createtime 則是為了時效。而存在。
其余字段不再過多解釋。
生成二維碼
借助PHP的QRCode庫,其實是很方便的。
<?php
error_reporting(E_ALL);
ini_set('error_reporting', '1');
session_start();
include "./phpqrcode/phpqrcode.php";
$value = uniqid();
$errorCorrectionLevel = "L";
$matrixPointSize = "4";
// session storage
$_SESSION['uuid'] = $value;
// 向數據庫中插入生成的數據
$link = mysql_connect('localhost', 'root', 'root') or die(mysql_error());
mysql_query('set names utf8');
mysql_select_db('test');
$createtime = date("Y-m-d H:i:s");
$account = 'guest';
$isscanned = 0;
$issuccess = mysql_query("insert into qrcode values('$value', '$account', '$createtime', $isscanned)") or die(mysql_error());
//var_dump($issuccess);
if($issuccess==1){
QRcode::png($value, false, $errorCorrectionLevel, $matrixPointSize);
}else{
echo "insert into db failed!";
}
?>
雖然代碼中向數據庫中插入了游客賬號,但是這并不影響接下來客戶端發送請求后對登陸用戶及信息的更改。
然后需要注意的是記得在代碼的開始處開啟session,不然有可能會出錯。
處理確認登陸請求
處理登陸請求其實也算是重中之重了。所以handler.php的責任義不容辭。
<?php
session_start();
header("Content-Type: text/json;charset=UTF-8");
$uuid = $_REQUEST['uuid'];
// echo $uuid;
// 獲取到數據庫中與此uuid一致的那一行的用戶信息
$link = mysql_connect('localhost', 'root', 'root') or die(mysql_error());
mysql_query('set names utf8');
mysql_select_db('test');
$resultset = mysql_query("select * from qrcode where id= '$uuid'") or die(mysql_error());
while(($row=mysql_fetch_array($resultset))) {
$result[] = $row;
}
mysql_close($link);
echo json_encode($result);
?>
至于作用嘛,就是網頁前臺那塊用于更改登陸者信息。使用ajax輪詢的方式對登錄表進行查詢,從而來實時的更新狀態信息。
前端
好了,后臺已經搭建好了,這個時候就可以好好的寫寫前端的代碼了。我本人不太懂設計這塊,所以就簡單的寫了下,聊表心意算了。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
<title>二維碼掃描登陸</title>
<style>
.container {
width: 600px;
height: 480px;
position: absolute;
background: gray;
left: 50%;
margin-left: -300px;
}
.header {
width: 100%;
height: 64px;
position: relative;
background: black;
}
.main {
width: 80%;
height: 340px;
position: relative;
left: 50%;
margin-left: -30%;
top: 12%;
background: url(921555.png) no-repeat;
background-size: contain;
}
ul {
margin: 0px;
padding: 0px;
width: auto;
list-style: none;
position: relative;
}
ul >li {
float: right;
position: relative;
}
/* 設計顯示二維碼的空間*/
.qrcontainer{
width: 300px;
height: 300px;
top: 64px;
position: relative;
background: green;
}
.qrcontainer > img {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<ul>
<font color="white" size="6" style="margin-top: 6px;">二維碼掃描登陸測試</font>
<li><font color="white" size="6"><a href="#">登陸</a>/ <a href="#">注冊</a></font></li>
</ul>
</div>
<div class="main">
<img id="photo" src="" />
</div>
</div>
<div class="qrcontainer">

</div>
<input type="hidden" name="uuid" value="<?php session_start(); echo $_SESSION['uuid'];?>"/>
</body>
<script src="jquery-2.2.4.min.js"></script>
<script>
$(document).ready(function(){
var uuid = document.getElementsByName('uuid')[0].value;
// 想法是通過ajax輪詢,請求服務器上的登錄狀態信息
$.ajax({
url: './handler.php',
type: 'POST',
async: true,
data: {
'uuid': uuid
},
timeout: 5000,
dataType: 'json',
success: function(result){
document.getElementById("photo").src = 'photo.jpeg';
$(".qrcontainer").css('display', 'none');
console.log(result);
},
error: function(){
console.log('額,AJAX請求出錯了!');
}
});
});
</script>
</html>
效果
觀看完人家阿里云的,再來看咱自己的。額,瞬間感覺檔次下降了好多啊。
首頁
先來看看首頁效果圖
掃碼
掃碼這塊,我沒有另外寫一個app。其實原理了解了就行了。 App的作用就是將掃描到的二維碼的UUID值,加上用戶的用戶名等信息傳給服務器。
這個時候服務器就可以根據UUID查找到剛才插入到數據庫上的信息,然后進行信息的更新操作即可。操作比較簡單,這里就不再進行演示了。
前臺通過ajax請求就可以獲取到:是誰登陸了?這些信息。
這里通過添加一張圖片來驗證確實通過了驗證請求。
查看一下后臺發送過來的數據,也可以進一步進行驗證的啦。
拓展
基本上效果已經實現的差不多了。但是做的仍然不夠好。我覺得可以從下面幾個角度進行加強。
輪詢
上面的代碼沒有進行輪詢處理。其實完全可以設置一個Inerval來進行的。這樣才能更加逼真的體現實時性的特點。
超時
想必您也已經看到了數據庫中設計好的createtime字段。之所以設置這樣的一個字段,就是為了讓二維碼在一定是的時段內有效。這樣可以進一步加強登錄操作的安全性。
至于優化部分,使用JavaScript很容易啦。不過多敘述。
掃描后失效
這一點可以通過isscanned字段進行控制。當然了,離不開ajax的配合。通過對此字段的“監控”。就可以很容易的實現這一個效果。
總結
回顧一下本次實驗。主要是實現了一個非權威的掃碼登陸功能,(雛形一個)。
然后根據代碼本身,找到了幾個可以進行優化和拓展的方向。想來進一步的話,做成一個更加完善的掃碼登陸,也會水到渠成的。