1. 程式人生 > >二維碼掃碼登入詳解【附簡易例項程式碼(html+php+ios)】

二維碼掃碼登入詳解【附簡易例項程式碼(html+php+ios)】

1.前言

      我們在寫一個不太瞭解的新功能的時候,又穩又快的一個方法就是借(chao)鑑(xi)其他的人的實現方法。所以我們先不急著開始寫程式碼,先看一下各網際網路巨頭都是如何實現的。

首先來看一下淘寶的掃碼登入:

這裡寫圖片描述

F12調出控制檯,可以看出淘寶一直在傳送請求檢視這個二維碼的狀態

這裡寫圖片描述

可以看出京東也是這麼做的,看到這裡大家都有點思路了把

2.準備

接著我們還是不著急寫程式碼,先把思路理清楚。這裡我們採用前後端分離的方法來實現這個功能(暫不考慮二維碼過期、該二維碼登入過一次等複雜情況,只實現掃碼登入功能)。

      2.1 首先梳理一下要準備的PHP介面,一共有3個:

          1.讓前端頁獲取唯一的QRUUID(唯一字串就可以)生成一個二維碼用的介面。
         2.APP端掃描到QRUUID後去請求的介面,功能是把使用者和這個QRUUID繫結(可以傳User_id或者token什麼的,具體看需求)。
         3.前端在獲取到第一個的介面返回的QRUUID後去輪詢請求的介面,功能是查詢這個QRUUID是不是被APP端掃描並繫結。

      2.2 然後是HTML頁的主要實現:

          其實就是Ajax請求PHP介面獲得QRUUID然後生成二維碼,接著使用setInterval() 方法去請求第三個PHP介面。(前端生成二維碼的開放API:

http://www.topscan.com/pingtai/)

      2.3 最後是APP端(以iOS為例)的實現:

          使用AVFoundation掃描二維碼獲得資訊,然後請求PHP介面將使用者資料和QRUUID繫結。

3.程式碼

      3.0 簡易資料庫表:

DROP TABLE IF EXISTS `qrcodelogin`;
CREATE TABLE `qrcodelogin` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `qruuid` varchar(15) NOT NULL DEFAULT ''
, `user_id` int(11) DEFAULT NULL, `user_token` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB;
SET FOREIGN_KEY_CHECKS = 1;

      3.1 先放上PHP的3個介面的程式碼:

<?php
//config.php 資料庫配置檔案
$db_host = '192.168.1.103';
$db_name = 'test';
$db_user = 'root';
$db_pwd = 'a123456';
<?php
/**
 * getqruuid.php
 * 用於前端獲取qruuid(二維碼唯一ID)使用
 *
 * User: caohan
 */

require('config.php');

$mysqli = new mysqli($db_host, $db_user, $db_pwd, $db_name);
if (mysqli_connect_error())
    echo mysqli_connect_error();
$mysqli->set_charset("utf8");

//生成隨機的UUID 用於二維碼顯示的內容 和 繫結用
$qruuid = substr(md5(uniqid(mt_rand(), true)), 0, 15);//生成uuid

$sql = "insert into qrcodelogin (qruuid) values ('". $qruuid ."')";
$result = $mysqli->query($sql);


if($result === false){
    echo $mysqli->error;
    echo $mysqli->errno;
}

$mysqli->close();

$arr = ['code'=>1, 'msg' => '生成qruuid成功','data'=>$qruuid];
echo json_encode($arr);
exit();
<?php
/**
 * bindqruuid.php
 * App端掃描二維碼獲得qruuid以後
 * 然後請求這個介面  二維碼的qruuid和使用者繫結並把使用者資訊傳入
 * (token或者user_info什麼的 具體看需求)
 *
 * User: caohan
 */

require('config.php');

$mysqli = new mysqli($db_host, $db_user, $db_pwd, $db_name);
if (mysqli_connect_error())
    echo mysqli_connect_error();
$mysqli->set_charset("utf8");

$qruuid = $_GET['qruuid'];
$user_id = $_GET['user_id'];
$user_token = $_GET['user_token'];

$sql = "update qrcodelogin set user_id='" . $user_id . "',user_token='" . $user_token . "' where qruuid='" . $qruuid . "'";
$result = $mysqli->query($sql);

if ($result === false) {
    echo $mysqli->error;
    echo $mysqli->errno;
}

$mysqli->close();
$arr = ['code' => 1, 'msg' => '繫結成功'];
echo json_encode($arr);
exit();
<?php
/**
 * checkqruuid.php
 * 用於前端頁輪詢 查詢該qruuid是否被繫結
 * 
 * User: caohan
 */

require('config.php');

$mysqli = new mysqli($db_host, $db_user, $db_pwd, $db_name);
if (mysqli_connect_error())
    echo mysqli_connect_error();
$mysqli->set_charset("utf8");

$qruuid = $_GET['qruuid'];

$sql = "select * from qrcodelogin where qruuid='" . $qruuid . "'";
$result = $mysqli->query($sql)->fetch_array();

if ($result === false) {
    echo $mysqli->error;
    echo $mysqli->errno;
}

$mysqli->close();

if (!is_null($result['user_id']))
    $arr = ['code' => 1, 'msg' => '登入成功', 'data' => $result];
else
    $arr = ['code' => 500, 'msg' => 'qruuid暫時未被繫結','data'=>$qruuid];

echo json_encode($arr);
exit();
?>

      3.2 HTML頁的程式碼:

<html>
    <head>
        <script  src="http://libs.baidu.com/jquery/1.7.2/jquery.min.js"></script><!--線上jq引用-->
        <title>這個一個二維碼登入頁Demo</title>
    </head>
    <body>
        <h4>
            這個一個二維碼登入頁Demo
        </h4>
        <h5>
            用APP掃描下方二維碼模擬登入
        </h5>
        <img id="qrcodeimg" />
    </body>

    <script>
        $.ajax({
            type: "GET",
            url: "getqruuid.php",
            data: {},
            success: function (result) {
                var data = JSON.parse(result);
                if (data.code == 1) {
                    //顯示到網頁上  免費線上二維碼生成的API
                    $("#qrcodeimg").attr('src', 'http://qr.topscan.com/api.php?text=' + data.data);
                    //輪詢 查詢該qruuid的狀態 直到登入成功或者過期(過期這裡沒判斷,留給大家)
                    var interval1= setInterval(function () {
                        $.ajax({
                            type: "GET",
                            url: "checkqruuid.php",
                            data: {'qruuid': data.data},
                            success: function (result) {
                                var data = JSON.parse(result);
                                if (data.code == 1) {
                                    alert('掃碼成功(即登入成功),進行跳轉.....');
                                    //停止輪詢
                                    clearInterval(interval1);
                                    //TODO 拿到需要的資訊 然後跳轉什麼的
                                }
                            }
                        });
                    }, 1000);//1秒鐘  頻率按需求
                }
            }
        });
    </script>
</html>

      3.3 APP的核心程式碼:

//
//  ViewController.m
//  QRCode


#import "ViewController.h"
#import "QRCodeViewController.h"

@interface ViewController () <QRCodeViewControllerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}

- (IBAction)scanCode:(UIButton *)sender {

    QRCodeViewController *qrVc = [[QRCodeViewController alloc] init];
    qrVc.delegate = self;
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:qrVc];

    // 設定掃描完成後的回撥
    __weak typeof (self) wSelf = self;
    [qrVc setCompletionWithBlock:^(NSString *resultAsString) {
        [wSelf.navigationController popViewControllerAnimated:YES];
//        [[[UIAlertView alloc] initWithTitle:@"掃描完成" message:resultAsString delegate:self cancelButtonTitle:@"好的" otherButtonTitles: nil] show];
    }];

    [self presentViewController:nav animated:YES completion:nil];
}

#pragma mark - 代理方法
- (void)reader:(QRCodeViewController *)reader didScanResult:(NSString *)result
{
    NSLog(@"%@",result);
    //模擬使用者已登入狀態
    //建立假的user_id和假的user_token用於繫結(根據實際需求傳遞引數)
    NSInteger user_id = 1;
    NSString *user_token = @"this_is_user_token";
    [self dismissViewControllerAnimated:YES completion:^{
        //請求服務端介面
        NSError *error;
        NSString *urlString = [NSString stringWithFormat:@"http://192.168.1.103/qrcodelogin/bindqruuid.php?qruuid=%@&user_id=%ld&user_token=%@",result,(long)user_id,user_token];
        //載入一個NSURL物件
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
        //將請求的url資料放到NSData物件中
        NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
        NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableLeaves error:&error];
        NSLog(@"接收到的資料為%@",jsonDic);
    }];
}

@end

4.實現效果

HTML登入頁

這裡寫圖片描述

APP掃碼過程

這裡寫圖片描述

掃描後的網頁

這裡寫圖片描述

5.專案GitHub地址