首頁  >  文章  >  後端開發  >  詳解edusoho實作掃碼登入功能實例

詳解edusoho實作掃碼登入功能實例

零下一度
零下一度原創
2017-06-30 15:51:023240瀏覽

一、專案介紹及需求

  edusoho是一套商業版的線上教育平台,專案本身基於symfony2框架開發,現在有一款自己的APP,要求不多修改edusoho自身程式碼的基礎上,實作客戶端對PC端掃碼登入。不多修改edusoho程式碼的原因是為了避免下次升級主版本時發生錯誤。

二、版本資訊及所需應用

edusoho 7.5.14

php   5.5.25

php   GD函式庫

memcache(這次使用memcache作為儲存介質,可用redis代替) 點我下載

phpqrcde(php產生二維碼外掛程式)

 

#三、實現想法

  點擊頁面掃碼按鈕,向php發送一個請求,php產生二維碼並把sign驗證字串儲存至memcache中,請求成功後,頁面展示二維碼等待掃碼,並使用ajax以輪詢的方式請求後台方法,查詢是否已掃碼。手機掃碼後訪問二維碼裡面的url鏈接,php保存已掃碼標識,並向ajax返回已掃碼狀態,前台頁面提示已掃碼,並再次發送是否已確認登錄的ajax輪詢。掃碼完成後,APP端顯示是否登入頁面,點選確認,向後台方法傳遞使用者名稱及sign驗證字串,後台驗證通過後,返回使用者名,sign及狀態碼至前端ajax。

  由於需求是不多改動edusoho自身程式碼,所以登入時借用edusoho本身的登錄,也就是把ajax回傳的使用者名稱填寫進使用者名稱框,sign填進密碼框,觸發登入的submit按鈕,只在登入的密碼驗證處加了幾行程式碼,把密碼驗證,改為了sign驗證。 (symfony2採用的登入方式是security設定化登錄,後面會講到在哪裡改動密碼驗證,不熟悉的可以參考security安全登入)

四、實作程式碼及步驟

1、產生登入二維碼

(1)先在custom下的routing.yml配置存取路由(其他方式路由請自行參考配置,以下方法的路由配置不再贅述)

(2)點選掃碼按鈕的js程式碼(可以把key存進cookie中,本範例直接寫進了頁面的隱藏網域)

   //点击扫码弹出框$('.scanqrcode').click(function (){
        $('.login-section').hide();//隐藏登陆框$('.qrcode').show();//弹窗$('.timeout').hide();
        $('.barcode-container.scanned .status.scanned, .barcode-container.scanned .mask').hide();
        $('.login_op').show();//显示遮罩层//请求二维码        $.ajax({
            type: "POST",
            dataType: "json",
            url: "/login/create/qrcode",
            success: function (data) {if(data.status==1){var qrcodeimg = '../../assets/img/qrcodeimg/'+data.msg+'.png';//把key放进隐藏域$('#key').val(data.msg);//替换二维码$('.qrcode-img').attr('src',qrcodeimg);//触发定时任务,查看是否已扫码var inter = setInterval("is_sacn_qrcode();",3000);
                    $('#timing').val(inter);
                }
            }
        });
    });

(3)寫createQrcode方法產生二維碼圖片的php程式碼(doString方法是產生sign字串的演算法,還請自行發明創造,產生結果每次都不一樣是最好的)

    //生成登录二维码public function CreateQrcodeAction(){ob_start();$url = 'http://'.$_SERVER['HTTP_HOST'];//获取当前的url$http = $url.'/login/mobile/scan/qrcode';//确认扫码的url方法$key = $this->getRandom(30);//存放在memcache中的键值,随机32位字符串$_SESSION['qrcode_name'] = $key;//把key当做图片的名字存在session里$sgin_data = $this->doString();//生成sign字符串的基本算法$sgin = strrev(substr($key,0,2)) . $sgin_data;//截取前两位并反转$value = $http.'?key='.$key.'&type=1';//二维码内容$errorCorrectionLevel = 'H';//容错级别$matrixPointSize = 8;//生成图片大小
        //生成二维码图片\QRcode::png($value, 'qrcode.png', $errorCorrectionLevel, $matrixPointSize, 0);$logo =     "assets/img/qrcodeimg_logo.png";//准备好的logo图片$QR = 'qrcode.png';//已经生成的原始二维码图if ($logo !== FALSE) {$QR = imagecreatefromstring(file_get_contents($QR));$logo = imagecreatefromstring(file_get_contents($logo));$QR_width = imagesx($QR);//二维码图片宽度$QR_height = imagesy($QR);//二维码图片高度$logo_width = imagesx($logo);//logo图片宽度$logo_height = imagesy($logo);//logo图片高度$logo_qr_width = $QR_width / 3;$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);
        }//输出图片$img = imagepng($QR, 'assets/img/qrcodeimg/'.$key.'.png');$return = array('status'=>0,'msg'=>'');if($img){$mem = new \Memcache();$mem->connect('127.0.0.1',11211);$res = json_encode(array('sign'=>$sgin,'type'=>0));//存进memcache,过期时间三分钟$mem->set($key,$res,0,180);//180$return = array('status'=>1,'msg'=>$key);
        }return $this->createJsonResponse($return);
    }

2、jquery彈出頁面二維碼並啟動ajax輪詢查詢是否掃碼

(1)顯示效果圖:

#(2)請求是否掃碼的js程式碼(未掃碼就一直輪詢,已掃碼關閉「查看是否已掃碼」方法,開啟「查看是否確認登入」的方法輪詢,關閉二維碼框清除所有方法)

//查看是否已扫码function is_sacn_qrcode (){
    $.ajax({
        type: "POST",
        dataType: "json",
        url: " /login/scan/qrcode",
        success: function (data) {if(data.status==1){//扫码成功$('.barcode-container.scanned .status.scanned, .barcode-container.scanned .mask').show();//取消定时任务,清除cookieclearInterval($('#timing').val());
                $('#timing').val('');////定时2秒关闭弹窗//setTimeout(function(){//    $('.qrcode').hide();//},2000);//查看是否已确认登录var is_login = setInterval("is_login();",3000);
                $('#is_login').val(is_login);//$.cookie('is_login', is_login);}else if(data.status==2){
                $('.timeout,.mask').show();//取消定时任务,清除cookieclearInterval($('#timing').val());
                $('#timing').val('');
            }
        }
    });
}

(3)查看是否已掃碼的php程式碼

  = ['qrcode_name' = ->connect('127.0.0.1',11211 = json_decode(->get(),(( = ('status'=>2,'msg'=>'已过期'(['type' = ('status'=>1,'msg'=>'成功' = ('status'=>0,'msg'=>'' ->createJsonResponse(

( 4)客戶端掃碼的php程式碼

    //移动设备扫码public function mobileScanQrcodeAction(Request $request,$key){$key = $_GET['key'];$url = 'http://'.$_SERVER['HTTP_HOST'];$agent=$_SERVER["HTTP_USER_AGENT"];if (!(strpos($agent, 'MicroMessenger') === false)) {// 获取版本号
            //preg_match('/.*?(MicroMessenger\/([0-9.]+))\s*/', $agent, $matches);$app_url = 'http://club.risecenter.com/wap_app.html';// 微信浏览器,跳转至下载APP页面(可判断非指定app浏览器都跳转至此页面)return $this->redirect($app_url);
        }$http = $url.'/login/qrcodedoLogin';//返回确认登录的链接$mem = new \Memcache();$mem->connect('127.0.0.1',11211);$data = json_decode($mem->get($key),true);$data['type']=1;//增加type值,用来判断是否已扫码$res = json_encode($data);$mem->set($key,$res,0,180);$http = $http.'?key='.$key.'&type=scan';$return = array('status'=>1,'msg'=>$http);return $this->createJsonResponse($return);
    }

3、掃碼成功後判斷是否確認登入

(1)掃碼成功效果圖:

(2)掃碼成功後查詢是否登入js程式碼(客戶端確認登入後把使用者名稱傳遞給ajax,js把使用者名稱和sign填到使用者名稱和密碼表單,觸發頁面隱藏的submit登入按鈕)

//查看是否已确认登录function is_login(){var key = $('#key').val();
    $.ajax({
        type: "POST",
        dataType: "json",
        url: "/login/entry/login",
        data:{
            key:key
        },
        success: function (data) {if(data.status==1){var uid = data.uid;var sign = data.sign;//取消定时任务,清除cookieclearInterval($('#is_login').val());
                $('#is_login').val('');//隐藏扫码成功$('.barcode-container.scanned .status.scanned, .barcode-container.scanned .mask').hide();//弹出已确认$('.confirmed,.mask').show();//定时1秒确认登陆setTimeout(function(){//确认登录$('#login_username').val(data.user);
                    $('#login_password').val(data.sign);
                    $('#login-form').submit();
                },1000);

            }else if(data.status==2){//取消定时任务,清除cookieclearInterval($('#is_login').val());
                $('#is_login').val('');
                alert(data.msg);
            }
        }
    });
}

(3)查詢是否已確認登入的php程式碼

    /**
     * 客户端扫码后登录
     * $sign  客户端扫码时传递标识,与memcache中的做对比
     * $key   网页端二维码中传递的key
     * $uid   客户端登陆后扫码传递的用户id
     * @return void     */public function qrcodeDoLoginAction(Request $request,$login,$key,$sign){$login = $_GET['login'];$key = $_GET['key'];$sign = $_GET['sign'];$mem = new \Memcache();$mem->connect('127.0.0.1',11211);$data = json_decode($mem->get($key),true);//取出memcache的值if($data['sign']!=$sign){//验证传递的sign$return = array('status'=>0,'msg'=>'验证错误');return $this->createJsonResponse($return);
        }else{if($login){//手机扫码网页登陆,把用户名存进memcache$data['login'] = $login;$res = json_encode($data);$mem->set($key,$res,0,180);$return = array('status'=>1,'msg'=>'登录成功');return $this->createJsonResponse($return);
            }else{$return = array('status'=>0,'msg'=>'请传递正确的用户信息');return $this->createJsonResponse($return);
            }
        }

    }

4、確認登入

  走到這裡,就到了這次掃碼登入的最後一步了,也是最關鍵的一步,不知道諸位看官們把symfony2的security安全登入機制看的怎麼樣了,原理先不管了,畢竟不在本次的討論範圍之內,直接說改哪好了。

/src/topxia/WebBundle/Handler/AuthenticationProvider.php 的checkAuthentication方法,可以直接改,也可以繼承到custom再改。

php程式碼如下:

5、二維碼過期設定

  為了安全考慮,設定二維碼過期是很關鍵的一個步驟,在所有的php程式碼裡,存放在memcache中的資料都有時間限制,本範例中的時間是3分鐘,過期後,memcache會刪除原來的資料記錄,當ajax請求不到資料的時候,要在頁面顯示二維碼已過期,要求重新刷新二維碼。

效果圖如下:

結論:

1、php掃碼登入只是一個確認的過程,在每次存取接口的時候,安全驗證尤其重要,本次方法未涉及驗證的演算法,請諸位根據自身項目進行補充調整,先有理念再說嘛。

2、對於ajax輪詢的方法是否low,嗯,low。還有更好的實現方式,例如websocket,goeasy等大家見仁見智,不過看似支付寶和京東的掃碼都是輪詢,不對請見諒。

3、本次掃碼登入只是一個概念,不只針對edusoho平台,所有的都可以移植過去使用,不過,做好安全就好。

4、前端二維碼框的html和css程式碼各位不會找我要了吧,畢竟你們都是大牛嘛。

5、能看到這裡,真的挺感謝,沒白寫一場,另外,大牛們打擊的時候手下留情些,我還有第二版呢,也許比這個好哦。

 

以上是詳解edusoho實作掃碼登入功能實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn