`
ssxxjjii
  • 浏览: 944882 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

实现手机扫描二维码页面登录,类似web微信-第四篇,服务器端

    博客分类:
  • IM
 
阅读更多

http://blog.csdn.net/otangba/article/details/8273952

 

终于到了服务器端,第三篇的手机客户端如果已经下载了的话,没有服务器是不能正常运行的。

服务器端要做得事很多,虽然逻辑不是很复杂,但是我们必须要分析清楚我们要做哪些事,请看下图:

通过这张图,我们看出,服务器端的接口一共有6个,分别处理:

 

  1. 手机客户端登录
  2. 首页
  3. 二维码图片流
  4. long polling维持
  5. 接收手机客户端已扫描的通知
  6. 接收手机客户端已确认登录的通知
那么一个一个解决
 
首先是手机客户端登录,在上一篇我们介绍的手机客户端登录我们仅仅模拟一下,因此用户只需要提交一个用户名,服务器则通过SHA1对用户名加密,将密文返回作为token。为了将来验证这个密文是否OK,我们将用户名和密文保存在redis内供将来验证使。
需要引用的包:
[javascript] view plaincopy
  1. var http = require('http'), url = require('url'), fs = require('fs'), querystring = require('querystring'),qrcode = require('qrcode'), UUID = require('uuid-js'), sha1 = require('sha1'), redis = require('redis'), redisClient = redis  
  2.         .createClient('10087''192.168.111.122'), redisKey = 'QRCODE_LOGIN_TOKEN';  

redis 的客户端也一并创建了,并设置了key
web服务的基础结构如下:
[javascript] view plaincopy
  1. http.createServer(function(req, res) {  
  2.     // parse URL  
  3.     var url_parts = url.parse(req.url);  
  4.     var path = url_parts.pathname;  
  5.     var uuid4 = UUID.create();  
  6.     var _sessionID = uuid4.toString();  
  7.     if (path == '/') {  
  8.         //...  
  9.     } else if (path == '/poll') {  
  10.         // console.log('polling');  
  11.           
  12.     } else if (path == '/qrcodeimage') {  
  13.         // 二维码的请求,参数为sessionID  
  14.   
  15.     } else if (path == '/moblogin') {  
  16.         // 返回用户名对应的token,简单采用sha1加密  
  17.           
  18.     } else if (path == '/scanned') {  
  19.         console.log('scanned');  
  20.           
  21.     } else if (path == '/confirmed') {  
  22.         console.log('confirmed');  
  23.           
  24.     } else {  
  25.         res.writeHead(200, {  
  26.             'Content-Type' : 'text/html; charset=UTF-8'  
  27.         });  
  28.         res.end();  
  29.     }  
  30. }).listen(9999, '192.168.111.109');  
  31. console.log('服务器已运行在端口9999.');  

通过分析,我们无非就是为这6个分支添加逻辑。
这次案例是一个试验,因此我们代码编写的也比较简单,如果使用类似express等框架的话,会更加方便一些。
 
先看看第一个接口,登录,返回sha1的token
[javascript] view plaincopy
  1. if (path == '/moblogin') {  
  2. <span style="white-space:pre">      </span>// 返回用户名对应的token,简单采用sha1加密  
  3.         var userName = urlDecode(url_parts.query);  
  4.         var token = sha1(userName);  
  5.         // userHash.set(token, userName);  
  6.         // 保存token到redis  
  7.         redisClient.hset(redisKey, token, userName);  
  8.         res.writeHead(200, {  
  9.             'Content-Type' : 'text/html; charset=UTF-8'  
  10.         });  
  11.         res.end(token);  
  12. <span style="white-space:pre">  </span>}  

下面是首页,如果用户敲击的url是一个不带参数的地址,事实上,用户初次访问肯定不带任何参数,而我们这个页面的目的是必须要有sessionID,因为首页内包含的2个子请求是必须具备sessionID参数的。因此我们要做url做一个分析和强制跳转:
[javascript] view plaincopy
  1. if (path == '/') {  
  2.         var sessionID = url_parts.query;  
  3.         if (typeof (sessionID) == "undefined" || sessionID == "") {  
  4.             // 访问首页没有参数,自动跳转  
  5.             res.writeHead(200, {  
  6.                 'Refresh' : '0; url=/?' + _sessionID,  
  7.                 'Content-Type' : 'text/html; charset=UTF-8'  
  8.             });  
  9.             res.end();  
  10.         } else {  
  11.             // 处理首页,刷新一条sessionID和二维码  
  12.             generateIndex(sessionID, req, res);  
  13.         }  
  14.     }  

也就是说当直接访问/的时候,服务器强制将请求重定向并包含sessionID信息
[javascript] view plaincopy
  1. function generateIndex(sessionID, req, res) {  
  2.   
  3.     fs.readFile('./index.html''UTF-8'function(err, data) {  
  4.         data = data.replace(/SESSIONID/g, sessionID);  
  5.         res.writeHead(200, {  
  6.             'Content-Type' : 'text/html; charset=UTF-8'  
  7.         });  
  8.         res.end(data);  
  9.     });  
  10.   
  11. }  

当访问的地址符合/?sessionID的时候,服务器读取一个html页面,并将其中的二维码和long polling需要的参数替换为sessionID
[html] view plaincopy
  1. <html>  
  2.     <head>  
  3.         <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>  
  4.         <script>  
  5.               
  6.             var poll = function() {  
  7.                 $.getJSON('/poll?SESSIONID', function(response) {  
  8.                     var cmd = response.cmd;  
  9.                     if (cmd == 'scanned') {  
  10.                         scanned();  
  11.                     } else if (cmd == 'pclogin') {  
  12.                         var username=response.username;  
  13.                         pclogin(username);  
  14.                     }  
  15.                     poll();  
  16.                 });  
  17.             }  
  18.             var pclogin = function(username) {  
  19.                 $('#output').text('欢迎您:' + username + ',您已成功登录');  
  20.             }  
  21.             var scanned = function() {  
  22.                 $('#output').text('已成功扫描,等待手机确认登录');  
  23.             }  
  24.             poll();  
  25.         </script>  
  26.     </head>  
  27.     <body>  
  28.         <p align="center"><img src="/qrcodeimage?SESSIONID">  
  29.         </p>  
  30.           
  31.     </body>  
  32. </html>  
二维码的请求在我们第二篇就已经介绍过,这里不再重复。
那么维持long polling的接口
[javascript] view plaincopy
  1. if (path == '/poll') {  
  2.         // console.log('polling');  
  3.         var sessionID = url_parts.query;  
  4.         var sessionObj = {  
  5.             'sessionID' : sessionID,  
  6.             'res' : res  
  7.         };  
  8.         clients.push(sessionObj);  
  9.         console.log('client added' + sessionObj);  
  10.     }  

在处理接收客户端完成扫描和确认登录的时候,逻辑比较类似,都是先验证用户的token是否存在,商用的话可能还要有些更安全的考虑
然后根据sessionID找到维持long polling的客户端对象,并且返回相关的操作指令
[javascript] view plaincopy
  1. function handleScanned(res, token, sessionID) {  
  2.     // console.log(">>>" + token + "," + sessionID);  
  3.     var success = false;  
  4.     if (typeof (token) != "undefined") {  
  5.         // 验证是否包含用户信息已确认是登录的用户  
  6.         var userName;  
  7.         redisClient.hget(redisKey, token, function(err, reply) {  
  8.             userName = reply;  
  9.             // console.log("username=" + userName);  
  10.             if (typeof (userName) != "undefined") {  
  11.                 // 用户存在  
  12.                 for ( var int = 0; int < clients.length; int++) {  
  13.                     var clientobj = clients[int];  
  14.                     var savedSession = clientobj.sessionID;  
  15.                     var client = clientobj.res;  
  16.                     if (savedSession == sessionID) {  
  17.                         // 页面存在  
  18.                         client.end(JSON.stringify({  
  19.                             cmd : 'scanned'  
  20.                         }));  
  21.                         clients.splice(int, 1);  
  22.                         success = true;  
  23.                         break;  
  24.                     }  
  25.                 }  
  26.             }  
  27.             res.writeHead(200, {  
  28.                 'Content-Type' : 'text/html; charset=UTF-8'  
  29.             });  
  30.             if (success) {  
  31.                 res.end("scanned");  
  32.             } else {  
  33.                 res.end("error");  
  34.             }  
  35.         });  
  36.   
  37.     }  
  38.   
  39. }  

至此,我们的完整的二维码扫描登录的流程就已经走完了。
放在服务器上运行一下,完全OK,如果想作为daemon的话可以使用forever包。
 
经过这几篇的介绍,我们不难发现其实这个效果的实现并不是很复杂,关键在于你要把整个逻辑理顺和想清楚。
同时由于这个案例涉及的技术也较多,技术不全面的话也很难形成完成的解决方案。
 
思考:
这个案例中还存在哪些问题
  1. 微信27秒是事出有因的,考虑到http请求有可能在客户端因为长时间无响应而被终止,因此27秒自动刷新long polling可以有效的防治连接断掉,而在我们这个案例里,并没有去实现这个功能。首先我觉得实现起来没有问题,不难,另外,这些点应该由你们自己去实现,我更加关注的是分析业务。
  2. 关于页面session的内涵,应该可以附加一些加密的信息,对于客户端只是传递这些信息,因此不涉及解密操作,而服务器端就可以验证sessionID的合法性,目前如果你访问/?的时候自己宿便敲sessionID也是可以的,服务器没有做任何验证和限制。
  3. 关于long polling客户端的response对象的维持和清理,在本例中我们直接采用了js的数组进行存储,因此每次都是遍历。如果商用,必然用采用哈希的方式来存储,同时可能还必须存储在数据库内。
  4. 本例只是在客户端确认登录之后在页面上显示确认登录,并没有跳转到某页面,但是实际应用的时候,可能会携带某个服务器生成的钥匙去redirect到某个url,只有目标地址确认这个钥匙是登录确认信息之后才会以某用户方式登录,这个还是希望大家能实现,逻辑很简单,只是本例略掉。
 
后续的文章,就不再就这个话题讨论了,我们会回到XMPP上,但是可能会把XMPP和我们这个案例做些结合。
例如客户端登录的不是web系统,而是XMPP
客户端确认登录以及提交扫描成功不是通过http,而是通过XMPP
web页面要实现BOSH连XMPP
这些话题我们会在后面的内容里不断收入的研究。
分享到:
评论

相关推荐

    C# aps.net MVC web微信三方扫码登录与授权登录

    【C# ASP.NET MVC Web微信三方扫码登录与授权登录】是一个关于使用C#编程语言、ASP.NET MVC框架,实现微信第三方登录功能的项目。在这个项目中,开发者将学习如何集成微信API,允许用户通过微信账号进行扫码登录或...

    springboot实现web端微信扫码登录项目(基于微信开放平台)

    在本文中,我们将深入探讨如何使用SpringBoot框架来实现一个基于微信开放平台的Web端扫码登录功能。微信扫码登录是一种安全、便捷的用户身份验证方式,它允许用户通过扫描二维码来授权登录,而无需输入用户名和密码...

    C# winform设计 钉钉 微信 二维码 扫码登录登录客户端 源码文件 CS架构

    在这个项目中,客户端是用户运行的WinForm应用,服务器端可能是钉钉或微信的API接口。 4. **二维码扫描**:二维码是一种二维条形码,能够存储更多的信息。在登录场景中,用户通过手机扫描电脑屏幕上的二维码完成...

    C#版微信登录--亲测有效.zip

    用户通过扫描二维码,将登录请求发送到微信客户端,微信客户端验证成功后将授权信息返回给第三方应用,从而完成登录。这种机制避免了用户在不安全的网络环境下直接输入账号密码。 4. **OAuth2.0授权框架**: 微信...

    网页微信扫码登录功能实现

    - **扫描二维码**:用户使用微信APP扫描网页上的二维码,微信服务器会识别并弹出授权页面。 - **用户授权**:用户在微信APP中确认授权后,微信服务器会将授权信息通过回调地址返回给网站。 - **获取令牌**:网站...

    guyandog-QR_BR-master -新增新版微信二维码识别.zip

    2. **前端二维码识别**:描述中提到的是在前端进行二维码识别,这通常涉及JavaScript库,如`qrcode-reader`或`ZXing`(Zebra Crossing),这些库允许浏览器直接处理图像并识别其中的二维码,无需服务器端处理。...

    js微信扫描二维码登录网站技术原理

    微信扫描二维码登录网站技术原理涉及到的技术主要包括OAuth2.0协议、JavaScript(JS)、二维码扫描技术、以及微信开放平台的接口应用等。下面详细介绍这些知识点。 1. OAuth2.0协议 OAuth2.0是一个开放标准,允许...

    web第三方微信扫码登录.rar

    用户在网页上点击“微信登录”按钮后,系统会跳转到微信授权页面,用户扫描二维码确认登录,微信服务器将授权码(code)发送回指定的回调地址。 3. **C#后端实现**: 在C#中,我们需要编写处理回调请求的代码,接收...

    TP5 调用微信小程序二维码

    总结,通过集成TP5和微信小程序的API,我们可以轻松地在Web端生成小程序二维码,便于用户扫描进入小程序。`Code.php`文件作为核心代码,应该包含了处理这些逻辑的函数或类,值得我们仔细研究和使用。在实践中,还...

    仿芝麻多合一收款二维码页面源码

    同时,可能还涉及到与第三方API的集成,如调用支付宝或微信的二维码生成接口,获取对应的支付二维码图像。 `使用说明.docx`文档很可能是为用户提供如何部署和使用这个源代码的指南。通常,这会包括以下步骤: 1. 将...

    MVC微信扫码登录.rar

    扫描二维码后,微信会回调预先配置的网页地址,通过查询参数传递登录状态,这时需要在后台处理这个回调,完成登录流程。 9. **错误处理和重试机制**:在实现过程中,可能会遇到网络问题或微信API服务不可用的情况,...

    微信PC端扫码控制器代码

    - 用户使用手机微信扫描二维码,微信服务器验证并授权。 - 微信服务器返回一个access_token和openid给应用程序。 - 应用程序使用这些凭证向微信服务器验证用户身份,并获取用户信息。 - 验证成功后,应用程序...

    最新先发信达付款PHP第三第四方支付源代码适用H5二维码支付微信收钱钱夹快捷支付功能.txt

    - **第四方支付**:又称为聚合支付或聚合服务提供商(PSP),它并不直接参与到资金结算环节,而是为商户提供包括但不限于多种支付渠道接入、订单管理、数据分析等功能在内的综合解决方案。 ##### (二)H5二维码...

    最新微信/支付宝/QQ二维码三合一制作程序PHP源码分享

    QQ钱包的二维码生成与微信支付、支付宝类似,也需要经过安全验证和加密处理。 现在,我们转向"微信QQ支付宝三合一收款码"这个主题。这个PHP源码程序很可能是为了帮助商家或个人创建一个可以同时接受来自微信、...

    最新游戏扫码登录源码(Safari+微信).zip

    扫码登录是一种常见的身份验证方式,它通过用户扫描二维码将身份信息从移动设备传输到其他设备上,如PC。在这个场景中,游戏可能会在Safari浏览器中展示一个二维码,用户使用微信扫描后完成登录。这涉及到的技术...

    带扫码登录的网页登录静态页面html模板

    4. **扫码登录原理**:扫码登录通常涉及到移动设备上的应用程序,如微信、支付宝或自定义App。用户通过扫描网页上显示的二维码,App会捕获相关信息,并向服务器发送请求。服务器验证后,返回一个临时的登录令牌,...

    PHP 二维码生成 QRCODE生成 源码

    PHP,作为一种广泛使用的服务器端脚本语言,因其开源、免费、跨平台的特性,常被用于网页开发。在信息化时代,二维码作为一种高效的信息载体,广泛应用于广告宣传、网址链接、支付凭证等多个场景。PHP结合二维码生成...

    二维码例子

    7. **后端实现**:在服务器端,可以使用编程语言如Python的`qrcode`库,Java的`ZXing`库,Node.js的`qr-image`库等来生成二维码。 8. **扫描与解码**:生成二维码的同时,也需要考虑如何解析二维码。市面上有很多...

    微信点餐系统微信小程序.zip

    它具有原生App的用户体验,但无需下载安装,只需在微信内搜索或扫描二维码即可使用。开发微信小程序需要掌握WXML(微信小程序的标记语言)和WXSS(微信小程序的样式语言),以及JavaScript来处理业务逻辑。 2. **...

    web weixin助手

    2. 获取二维码:验证成功后,服务器会返回一个二维码,用户需在手机微信上扫描并确认登录。 3. 服务器确认:手机端确认后,服务器会向Web客户端发送一个确认信号,完成登录。 二、微信Web协议收发消息 收发消息是...

Global site tag (gtag.js) - Google Analytics