初涉扫码登录:edusoho实现客户端扫码登录(简版…

2018-06-22 05:21:59来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

一、项目简介及需求

  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();
                //取消定时任务,清除cookie
                clearInterval($('#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();
                //取消定时任务,清除cookie
                clearInterval($('#timing').val());
                $('#timing').val('');
            }
        }
    });
}

(3)查看是否已扫码的php代码

    /**
     * 查看是否已扫码
     */
    public function isScanQrcodeAction(){

        $key = $_SESSION['qrcode_name'];
        $mem = new \Memcache();
        $mem->connect('127.0.0.1',11211);
        $data = json_decode($mem->get($key),true);
        if(empty($data)){
            $return = array('status'=>2,'msg'=>'已过期');
        }else{
            if($data['type']){
                $return = array('status'=>1,'msg'=>'成功');

            }else{
                $return = array('status'=>0,'msg'=>'');
            }
        }

        return $this->createJsonResponse($return);
    }

(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;
                //取消定时任务,清除cookie
                clearInterval($('#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){
                //取消定时任务,清除cookie
                clearInterval($('#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、能看到这里,真的挺感谢,没白写一场,另外,大牛们打击的时候手下留情些,我还有第二版呢,也许比这个好哦。

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:PHP文件是什么?如何打开PHP文件?

下一篇:PHP面向对象之标识对象