php/socket.io实现扫码登录
2016-05-07 22:59
471 查看
首先来先看张流程图,了解下原理
服务环境
后端web服务器: 80端口 php 负责生成二维码 生成uuid(这个很重要,后边会提到) 解析token等
web端: javascript 实现链接建立,信息发送
app端: javascript 实现登录确认(惭愧 ios学了好久就会加载个webview,网络编程更是一塌糊涂,只能拿webview代替原生了)
socket服务端:8888端口 node.js 负责管理socket链接 交换数据
首先是socket服务器
为什么决定用node来实现呢?其实刚开始准备用php的socket来实现,结果发现php socket网上几乎找不到什么资料,好不容易找到几个,一看日期,好家伙,2006年的,果断不敢用,随后发现了一个php的socket框架workerman,框架封装的很好,几乎不需要考虑套接字,协议也可以自己定义,但是我只想做一个demo,正巧最近被逼着搞node,于是就决定用node来做后端.
搭建socket服务器
node服务器的搭建非常简单,在我另一篇博文中有详细介绍,这里不多介绍,详见,/article/9187520.html
整个socket服务需要三个扩展:
socket.io 一看就是提供服务的
winston 这个是记录日志的,方便调试
express 这个是干啥的我也不知道,不过不装的话老报错,node二把刀水平,有知道的大神还望告知,
安装包很简单
首先建立个package.json文件,这个文件你可以理解成apache的httpd.conf
内容如下:
其中dependencies由脚本生成,无需填写,然后安装扩展,记着root权限哦
然后编写个conf.json的脚本配置文件,本身没多少东西,你也可以直接写进代码里面,内容如下
最后编写服务端代码: 如下
需要说的是,初始化链接后,每一个链接的客户端都对应一个socket的实例,即socket.id不同,我们也是通过这个将信息发送到指定的链接上去,node 的socket模块封装很好,我们只需要稍微加点业务逻辑进去即可,uuid可以理解为用户的标示,一个用户对于一个链接,我们可以通过用户标示找到socket.io链接
第二步是建立后端服务器用于生成二维码,生成uuid,验证token
这个很简单 如何生成二维码可以用谷歌的api 也可以用php的Qrcode包,网上有,而且很简单,不啰嗦了,实现代码如下:
注意:多用户的情况下uuid一定要唯一 不重复 这很重要
第三步编写web端脚本index.html如下:
socket.io为客户端socket的实现脚本,你可以在cdnjs上下载到,我将它下载到本地了
第四部分为app端的模拟代码如下
最后是流程演示
1.开启服务node sokcet.io服务如下
2.通过浏览器访问index.html获取二维码 链接node service
socket链接可以通过控制台来查看
service端收到请求 建立连接
3.通过浏览器访问app.html模拟手机端授权
然后点击确认登陆 控制台输出登陆成功
4.完成扫码登录web端跳转
我们来看一下日志可以得到整个流程
第一行 service start 表示服务启动
第二行 connection 是web端扫码后进行链接
第三行表示收到web端发送的uuid 并保存
第四行是app链接
第五行输出了app 确认登陆 登陆成功
后边是链接断开信息
以上就是扫码登录的思路及实现demo 实质上也可以通过轮询来实现 轮询前后端反而更容易编写写
可以参考我的另一篇博文
/article/9187519.html
所有代码可以在这里找到
https://code.csdn.net/zhangsheng_1992/socket/tree/master
服务环境
后端web服务器: 80端口 php 负责生成二维码 生成uuid(这个很重要,后边会提到) 解析token等
web端: javascript 实现链接建立,信息发送
app端: javascript 实现登录确认(惭愧 ios学了好久就会加载个webview,网络编程更是一塌糊涂,只能拿webview代替原生了)
socket服务端:8888端口 node.js 负责管理socket链接 交换数据
首先是socket服务器
为什么决定用node来实现呢?其实刚开始准备用php的socket来实现,结果发现php socket网上几乎找不到什么资料,好不容易找到几个,一看日期,好家伙,2006年的,果断不敢用,随后发现了一个php的socket框架workerman,框架封装的很好,几乎不需要考虑套接字,协议也可以自己定义,但是我只想做一个demo,正巧最近被逼着搞node,于是就决定用node来做后端.
搭建socket服务器
node服务器的搭建非常简单,在我另一篇博文中有详细介绍,这里不多介绍,详见,/article/9187520.html
整个socket服务需要三个扩展:
socket.io 一看就是提供服务的
winston 这个是记录日志的,方便调试
express 这个是干啥的我也不知道,不过不装的话老报错,node二把刀水平,有知道的大神还望告知,
安装包很简单
首先建立个package.json文件,这个文件你可以理解成apache的httpd.conf
内容如下:
{ "name": "IoService", "version": "0.0.1", "description": "Socket.io Service", "dependencies": { "express": "^4.13.4", "socket.io": "^1.4.6", "winston": "^2.2.0" } }
其中dependencies由脚本生成,无需填写,然后安装扩展,记着root权限哦
npm install --save express npm install --save socket.io npm install --save winston
然后编写个conf.json的脚本配置文件,本身没多少东西,你也可以直接写进代码里面,内容如下
{ "port": 8888, "log_level_logger": "info" }
最后编写服务端代码: 如下
//加载配置文件 var fs = require('fs'); var file = __dirname + "/" + 'conf.json'; var config = JSON.parse(fs.readFileSync(file, 'utf8')); var port = config['port']; var loggerLevel = config['log_level_logger']; //初始化日志记录 var winston = require('winston'); var logger = new (winston.Logger)({ transports: [ new (winston.transports.Console)({level: loggerLevel, timestamp: true}), new (winston.transports.File)({ filename: 'access.log',json: false}) ] }) //加载socket.io模块 监听指定端口 var http= require('http'); var io = require('socket.io').listen(port); logger.info('service start'); //定义一个list存放uuid 每一个uuid对应一个socket id var UUIDMap = {}; io.sockets.on('connection', function (socket) { logger.info('connection:', socket.id); var UUID; //客户端进行uuid与socket.id绑定 socket.on('register', function(data){ var regUUID = data['uuid']; //如果存在 解决刷新二维码造成的uuid不一致问题 if (UUID != null) { delete UUIDMap[UUID]; } UUID = regUUID; UUIDMap[UUID] = socket.id; logger.info('save in UUIDMap', UUID); }); //手机端确认登陆 socket.on('confirm',function(data){ //提示web端 手机端扫码成功 并将token令牌返回 replayToDisplayer(data, 'result'); //同时提示手机端 验证成功 socket.emit('success', { result: 'success' }) logger.info('mobile comfrim submit'); }); //客户端断开链接 socket.on('disconnect', function () { logger.info('disconnect', socket.id); if (UUID != null) { logger.info('delete ', UUID); delete UUIDMap[UUID]; } }); }); /** * 向指定web端发送信息 * * @param {json} data 要返回的数据 * @param {string} event 要回调客户端的监听事件 * @returns {undefined} */ function replayToDisplayer(data, event) { var submitUUID = data['uuid']; var displayerSocket = findSocketByUUID(submitUUID); if (displayerSocket != null) { logger.info('find socket and emit back ', submitUUID); displayerSocket.emit(event, data); } } /** * 通过uuid查找socket connection id * * @param {uuid} data 要返回的数据 */ function findSocketByUUID(UUID) { var targetSocketID = UUIDMap[UUID]; if (targetSocketID != null) { var targetSocket = io.sockets.connected[targetSocketID]; if (targetSocket != null) { return targetSocket; } else { logger.info('cant find target socket by uuid: ', UUID); } } else { logger.error('cant find target socket id by uuid: ', UUID); } return null; }
需要说的是,初始化链接后,每一个链接的客户端都对应一个socket的实例,即socket.id不同,我们也是通过这个将信息发送到指定的链接上去,node 的socket模块封装很好,我们只需要稍微加点业务逻辑进去即可,uuid可以理解为用户的标示,一个用户对于一个链接,我们可以通过用户标示找到socket.io链接
第二步是建立后端服务器用于生成二维码,生成uuid,验证token
这个很简单 如何生成二维码可以用谷歌的api 也可以用php的Qrcode包,网上有,而且很简单,不啰嗦了,实现代码如下:
<?php include 'qrcode/phpqrcode.php'; //uuid 唯一的标示符 用于指定客户端收发信息 $uuid = 'abc123'; //生成二维码文件 $filename = 'qrcode'.time().mt_rand(1000,9999).'.png'; //二维码中包含的数据 $data = [ "ip"=>'127.0.0.1', "port"=>'8888', 'exprise'=>time()+60, 'uuid'=>$uuid ]; try{ QRcode::png('$data','temp/'.$filename,'L',15); echo json_encode(['code'=>1,'message'=>'temp/'.$filename,'uuid'=>$uuid]); }catch(\Exception $e) { echo json_encode(['code'=>0,'message'=>$e->getMessage()]); }
注意:多用户的情况下uuid一定要唯一 不重复 这很重要
第三步编写web端脚本index.html如下:
<span style="font-size:12px;"><!Doctype html> <html> <head> <title>扫码登录demo</title> <meta charset="utf-8"></meta> </head> <body> <div style='margin:100px auto;width:80%;text-align:center'> <img src="" class="qrcode" style="display:none;margin:0 auto;"/><br /> <p></p><br /> <button class='button' onclick="getQrcode()" style='font-size:16px'>获取二维码登陆</button> </div> <script type="text/javascript" src="js/socket.io.js"></script> <script type="text/javascript" src="js/jquery.min.js"></script> <script type="text/javascript"> var timeLimit = 60; var uuid; /** * 获取二维码 */ function getQrcode(){ $.ajax({ type: 'POST', url: 'index.php', data: {}, dataType: 'json', success: function(data){ if(data.code === 1){ $('.qrcode').attr('src',data.message); $('.qrcode').show(); $('.button').attr('disabled',true); uuid = data.uuid; countDown(); init(data.uuid); console.log('生成二维码成功,正在建立链接...'); }else{ console.log(data.message); } } }); } /** * 刷新计时器 */ function countDown(){ var id = setInterval(function (){ var str = '二维码有效期剩余:'+timeLimit+'秒'; $('.button').html(str); if(timeLimit >0){ timeLimit--; }else{ timeLimit = 60; clearInterval(id); $('.button').html('获取二维码登陆'); $('.button').attr('disabled',false); } },1000); } /* * 初始化链接 */ function init(uuid) { var socket = io.connect('http://127.0.0.1:8888'); //向服务器发送uuid绑定socket.id socket.emit('register',{uuid:uuid}); //手机端扫码确认登陆后 socket.on('result',function(data){ //这里可以拿到data.token 拿到后就可以进行登陆了 console.log("登陆成功"+'token='+data.token); //后续操作 }); } </script> </body> </html></span>
socket.io为客户端socket的实现脚本,你可以在cdnjs上下载到,我将它下载到本地了
第四部分为app端的模拟代码如下
<span style="font-size:12px;"><!Doctype html> <html> <head> <title>模拟app扫码验证demo</title> <meta charset="utf-8"></meta> </head> <body> <div style='margin:100px auto;width:80%;text-align:center'> <p>注:现在模拟扫码的结果</p> <p>url:http://127.0.0.1</p> <p>port:8888</p> <p>uuid:abc123</p> <p>token:token</p> <div style='margin:0 auto;text-align:center' class="result"> <p class="notice">扫码验证完毕!</p> <button onclick="confrimYes()">确认登陆</button> </div> </div> <script type="text/javascript" src="js/socket.io.js"></script> <script type="text/javascript" src="js/jquery.min.js"></script> <script type="text/javascript"> //这部分应该是扫码解析出来的 现在只做模拟 var url = 'http://127.0.0.1'; var port = 8888; var uuid = 'abc123'; var token = 'token'; serviceUrl = url + ':' +port; var socket = io.connect(serviceUrl); socket.on('success',function(data){ console.log("登陆成功"+'message'+data.result); }); //确认登陆 function confrimYes(){ socket.emit('confirm',{uuid:uuid,token:token}); } </script> </body> </html></span>
最后是流程演示
1.开启服务node sokcet.io服务如下
2.通过浏览器访问index.html获取二维码 链接node service
socket链接可以通过控制台来查看
service端收到请求 建立连接
3.通过浏览器访问app.html模拟手机端授权
然后点击确认登陆 控制台输出登陆成功
4.完成扫码登录web端跳转
我们来看一下日志可以得到整个流程
第一行 service start 表示服务启动
第二行 connection 是web端扫码后进行链接
第三行表示收到web端发送的uuid 并保存
第四行是app链接
第五行输出了app 确认登陆 登陆成功
后边是链接断开信息
以上就是扫码登录的思路及实现demo 实质上也可以通过轮询来实现 轮询前后端反而更容易编写写
可以参考我的另一篇博文
/article/9187519.html
所有代码可以在这里找到
https://code.csdn.net/zhangsheng_1992/socket/tree/master
相关文章推荐
- ContentProvider权限设置
- 2016/5/6 thinkphp ①框架 ② 框架项目部署 ③MVC模式 ④控制器访问及路由解析 ⑤开发和生产模式 ⑥控制器和对应方法创建 ⑦视图模板文件创建 ⑧url地址大小写设置 ⑨空操作空控制器 ⑩项目分组
- 2016/5/7 PHP入门了解
- 利用smtp协议发送带附件的邮件
- Yii2.0 RESTful Web服务(1)
- 系统时钟 硬件时钟 系统时间 硬件时间 ntpd ntpdate
- php与数据库的连接运行
- PHP数组运算符
- PHP简单的登录判断
- 基于thinkphp的cms学生学籍管理系统
- Yii表单的使用
- Yii-Unable to verify your data submission 错误(CSRF)
- 关于php数据库随笔记录
- PHPCMS v9 自定义表单添加验证码验证
- php-生成验证码
- ContentProvider使用拾遗
- 传输协议ftp、tftp、sftp
- 谷歌趋势 php
- Yii2.0模型层数据验证和thinkPHP3.2框架模型层数据验证对比
- Servlet3.0中使用getPart进行文件上传