基于SignalR的消息推送与二维码描登录实现

1 概要说明

    使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛。为了满足ios、android客户端与web短信平台的结合,特开发了基于SinglarR消息推送机制的扫描登录。本系统涉及到以下知识点:

    SignalR:http://signalr.net/ 这官网,ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程。实时 Web 功能是指这样一种功能:当所连接的客户端变得可用时服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。

    二维码:使用的QRCode类库,https://github.com/jeromeetienne/jquery-qrcode

    MVC5:开发环境是基于MVC5

2、系统关系图

    在实现本功能前,有点不是太确定能否拿下。

    所谓万事开头难,通过查询想资料及自己归纳分析:系统涉及到手机客户端、浏览者、服务端,实现扫描登录也就是三者之间是如何协调工作的。通过axure画出如下关系图:

移动客户端、浏览者、服务端三者协作关系图

    【M】:表示移动端   【B】:表示浏览者(浏览器客户端)  【S】:服务端,消息推送者及扫描认证接口发布者

    步骤说明:

    Step(步骤)1  ,【B】浏览登录页面,Step2【S】产生一个标识符UUID,并推送给B,生成登录二维码;

    Step3,【M】扫描二维码,前提条件是【M】已登录,Step4【M】解析二维码信息获取UUID;

    Step5,【M】向服务端发送UUID+登录信息,Step6【S】对UUID+登录信息进行相关解析认证,Step6 UUID认证,不通过认证,则到Step6-1 重新生成UUID循环Step 2与并Step6-2 返回给【M】UUID认证失败原因,Step6 通过认证,Step6-2转到登录信息认证,Step 7登录信息认证,失败Step7-3重新生成UUID循环Step 2,成功则Step7-1推送给【B】跳转到首页。

3、SignalR循环消息推送

3.1 引用SignalR

    由于本人用的是VS15Preview4,可以直接使用Nuget可视化管理工具进行安装:Tools—>Nuget Package Manager—>Manage Nuget Packages for Solution…,打开以下界面:

    在Browser 标签下输入SignalR,查询到Microsoft.AspNet.SignalR

    找到对应的项目,点击“Install”安装按钮即可引用相关类库,同时应用下载相关js库。

    关于SignalR的知识点,可以到官网 http://www.asp.net/signalr 进行深入学习。

3.2 服务端SignalR实现

    服务端要向客户端推送UUID,对于UUID唯一标识符,具有重要特性:(1)有时间限制,120秒之内扫码有效;(2)具有一定的状态。对应的声明周期就是:生成—>推送—>状态判断—>手机端扫描—>验证UUID—>状态判断—>销毁等系列过程。

    服务端的核心代码将单独建立一个项目去实现:

3.2.1 Nofifier.cs通知类

    本类将连接QRCodeHub与SessionTimer


3.2.2 QRCodeHub.cs SignalR核心实现

    SignalR的核心代码:

using Microsoft.AspNet.SignalR;
using System.Threading.Tasks;

namespace TxSms.SingalR {    

   /// <summary>/// 二维码推送    
   
/// </summary>//[HubName("qrcode")]public class QRCodeHub : Hub{    
       
/// <summary>/// 给客户端发送时间间隔    
       
/// </summary>/// <param name="time"></param>public void SendTimeOutNotice(int time){Clients.Client(Context.ConnectionId).alertClient(time);}      
     
       
public void CheckElapsedTime(int time){Clients.Client(Context.ConnectionId).sendElapsedTime(time);}        
       
       
/// <summary>/// 发送二维码UUID内容      
       
/// </summary>/// <param name="uuid"></param>public void SendQRCodeUUID(string uuid){Clients.Client(Context.ConnectionId).sendQRCodeUUID(uuid);}      

       
/// <summary>/// Called when the connection connects to this hub instance.      
       
/// </summary>/// <returns>A <see cref="T:System.Threading.Tasks.Task" /></returns>public override Task OnConnected(){SessionTimer.StartTimer(Context.ConnectionId);      return base.OnConnected();}        

         /// <summary>/// Called when a connection disconnects from this hub gracefully or due to a timeout.        /// </summary>/// <param name="stopCalled">/// true, if stop was called on the client closing the connection gracefully;        /// false, if the connection has been lost for longer than the        /// <see cref="P:Microsoft.AspNet.SignalR.Configuration.IConfigurationManager.DisconnectTimeout" />.        /// Timeouts can be caused by clients reconnecting to another SignalR server in scaleout.        /// </param>/// <returns>A <see cref="T:System.Threading.Tasks.Task" /></returns>public override Task OnDisconnected(bool stopCalled){SessionTimer.StopTimer(Context.ConnectionId);            return base.OnDisconnected(stopCalled);}      

     
/// <summary>/// Called when the connection reconnects to this hub instance.        /// </summary>/// <returns>A <see cref="T:System.Threading.Tasks.Task" /></returns>public override Task OnReconnected(){          
           
if (!SessionTimer.Timers.ContainsKey(Context.ConnectionId)){SessionTimer.StartTimer(Context.ConnectionId);}            return base.OnReconnected();}        

       
/// <summary>/// 重置时钟    
       
/// </summary>public void ResetTimer(){SessionTimer timer;      
          
if (SessionTimer.Timers.TryGetValue(Context.ConnectionId, out timer)){timer.ResetTimer();}          
           
else{SessionTimer.StartTimer(Context.ConnectionId);}}        
/// <summary>/// 发送普通消息        
       
/// </summary>/// <param name="name"></param>/// <param name="message"></param>public void Send(string name, string message){Clients.All.addNewMessageToPage(name, message);}} }

3.2.3 SessionTimer.cs 对应客户端时钟

    对【B】来说,每个都产生一个timer,进行按1s间隔发送消息。

using System;
using System.Collections.Concurrent;
using System.Timers;

namespace TxSms.SingalR {    
   
public class SessionTimer : IDisposable{

        
/// <summary>/// 存储客户端对应的Timer    
       
/// </summary>public static readonly ConcurrentDictionary<string, SessionTimer> Timers;      
       
private readonly Timer _timer;        static SessionTimer(){Timers = new ConcurrentDictionary<string, SessionTimer>();}    
     
       
/// <summary>/// 构造函数        /// </summary>/// <param name="connectionId"></param>private SessionTimer(string connectionId){ConnectionId = connectionId;_timer = new Timer{Interval = Utility.ActivityTimerInterval()};_timer.Elapsed += (s, e) => MonitorElapsedTime();_timer.Start();}      
     
       
public int TimeCount { get; set; }        

       /// <summary>/// 客户端连接Id      
       
/// </summary>public string ConnectionId { get; set; }      
       
/// <summary>/// 启动Timer      
       
/// </summary>/// <param name="connectionId"></param>public static void StartTimer(string connectionId){            
           
var newTimer = new SessionTimer(connectionId);        
          
if (!Timers.TryAdd(connectionId, newTimer)){newTimer.Dispose();}}        
       
       ///
<summary>/// 停止Timer        /// </summary>/// <param name="connectionId"></param>public static void StopTimer(string connectionId){SessionTimer oldTimer;            if (Timers.TryRemove(connectionId, out oldTimer)){oldTimer.Dispose();}}        

       /// <summary>/// 重置Timer      
       
/// </summary>public void ResetTimer(){TimeCount = 0;_timer.Stop();_timer.Start();}        

       public void Dispose(){            // Stop might not be necessary since we call Dispose            _timer.Stop();_timer.Dispose();}        
           
       
/// <summary>/// 给客户端发送消息  
      
/// </summary>private void MonitorElapsedTime(){Utility.ClearExpiredUUID();            var uuid = Utility.GetUUID(ConnectionId);            //if (TimeCount >= Utility.TimerValue())            //{            //    StopTimer(ConnectionId);            //    Notifier.SendQRCodeUUID(ConnectionId, uuid);            //    Notifier.SessionTimeOut(ConnectionId, TimeCount);            //}            //else            //{            Notifier.SendQRCodeUUID(ConnectionId, uuid);Notifier.SendElapsedTime(ConnectionId, TimeCount);            //}TimeCount++;            if (TimeCount > 1000){TimeCount = 0;}}} }

3.2.4 Utility.cs 基础配置

    满足时钟、获取QRCode等

using TxSms.Actions;

namespace TxSms.SingalR {  
   
internal class Utility{      
       
public static int IntNum = 0;    
       
/// <summary>/// 时间间隔      
       
/// </summary>/// <returns></returns>public static int TimerValue(){            return 1000;}      

       
public static double ActivityTimerInterval(){        
              
return 1000.0;}      
 
       /// <summary>/// 获取当前UUID      
       
/// </summary>/// <returns></returns>public static string GetUUID(string connectionId){            try{                var model = new QRCodeAction().GetValidModel(connectionId);                return model.ToJson(connectionId);}            catch{                return "ERROR";}}        

       /// <summary>/// 删除过期UUID      
       
/// </summary>public static void ClearExpiredUUID(){IntNum++;            if (IntNum <= 1000) return;            new QRCodeAction().ClearExpiredUUID();IntNum = 0;}} }

3.2.5 SignalR在MVC中启动配置

    在MVC中,启动项目进行如下配置:

3.2.6 其他类库说明

    QRCodeAction.cs:维护UUID,创建、保存、状态更改、删除等。

    QRModel.cs:UUID实体

    所有文件,可在《6、相关文件》中下载。

3.3 客户端SignalR实现

    添加SignalR js库:

    <script type="text/javascript" src="~/Scripts/jquery.signalR-2.2.1.min.js"></script><script type="text/javascript" src="~/signalr/hubs"></script

    两者必须都引用。

    调用接口如下:

   

    以上代码包括相关二维码的生成。

4、二维码的生成与存储数据解析

4.1 二维码的生成   

    二维码类库选择https://github.com/jeromeetienne/jquery-qrcode 一个QRCode原生态js类库,jquery对其进行了扩展。

    添加script标签:

    <script type="text/javascript" src="~/Scripts/qrcode.min.js"></script><script type="text/javascript" src="~/Scripts/jquery.qrcode.min.js"></script>

    定义div标签,用来呈现二维码:


    呈现二维码:

                $("#divQRCode").html("");$('#divQRCode').qrcode({ width: 180, height: 180, correctLevel: 0, text: codeUUID });

    通过3与4,可实现具有120秒生命周期二维码的生成,对于不同的浏览者,生成的二维码是不同的,效果如下:

4.2 二维码存储的是什么

    二维码生成了,但是存储的是什么呢?首先我们看下以下的二维:

    显然,扫描这两个图片上的二维码会得到不同的结果。

    在本系统中,二维码存储的是一个json对象,格式为:

{"connectionid":"19c12e95-26d7-410c-8292-2a3afdd1a4da","uuid":"a04702df-6a52-4e1c-be8b-9b3dbeef4d72","islogin":0,"isvalid":1}
connectionid:客户端与SignalR联系的id,其格式为Guid

    • uuid:对应connectionid产生的一个唯一标识符,其格式为Guid

    • islogin:当前connectionid连接是否已登录,1—>表示登录,0—>未登录

    • isvalid:当前connectionid对应的uuid是否有效,1—>表示有效,0—>表示失效

    手机客户端扫描之后,可根据这些参数情况进行判断,是否向服务端发送请求。在做扫描应用(比如扫描登录)时,要依据业务场景进行消息传递,生成对应二维码,并不局限于json对象、url地址等。

5、扫描认证接口

    为了满足【M】端扫描之后,提交UUID+用户信息进行认证,建立QRCode API接口。接口任务比较简单,就是对UUID合法性进行判断,然后判断用户信息登录情况,更改UUID的登录状态。

5.1 输入参数


5.2 输出参数


5.3 API接口


6、总结与下载

    二维码应用比较广泛,记得去北京的故宫旁边的中山公园,里面的古树也有二维码,扫描可查看相关联信息。紧紧对于二维码而言就是存储有限信息,但就是这有限的信息,可以将庞大的信息系统连接一起,所用的应用不是前沿技术的突破,而是我们思考问题方式的转变、思维角度的变化。由于二维码具有信息存储的独特性,可在以下方面应用:

    • 信息获取(名片、地图、WIFI密码、资料)

    • 网站跳转(跳转到微博、手机网站、网站)

    • 广告推送(用户扫码,直接浏览商家推送的视频、音频广告)

    • 手机电商(用户扫码、手机直接购物下单)

    • 防伪溯源(用户扫码、即可查看生产地;同时后台可以获取最终消费地)

    • 优惠促销(用户扫码,下载电子优惠券,抽奖)

    • 会员管理(用户手机上获取电子会员信息、VIP服务)

    • 手机支付(扫描商品二维码,通过银行或第三方支付提供的手机端通道完成支付)

    由于最近在做短信业务平台,将二维码应用到营销管理中,每个业务人员具有独立的推广二维码,客户扫码可进行短信测试,若注册成为会员则就是本业务人员的直属客户,可查看《二维码在短信业务应用的初步构思》。

    最后,上传《基于SignalR的消息推送与二维码描登录实现》主要文件下载:http://files.cnblogs.com/files/zsy/signalr%E4%B8%8Eqrcode.rar

相关文章:

  • ASP.NET SignalR 高可用设计

  • ASP.NET SignalR 2.0入门指南

  • SignalR SelfHost实时消息,集成到web中,实现服务器消息推送

  • ASP.NET WebHooks Receivers 介绍-WebHooks 让其变得便捷

  • Signalr系列之虚拟目录详解与应用中的CDN加速实战

  • 采用HTML5+SignalR2.0(.Net)实现原生Web视频

  • 基于.NET SingalR,LayIM2.0实现的web聊天室

原文地址:https://github.com/fanpan26/LayIM_NetClient/


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

原文地址:http://www.cnblogs.com/zsy/p/5882034.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328426.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java调用exe阻塞

转载自 Java调用exe阻塞 今天遇到了个奇怪的问题&#xff0c;用VC写了个小程序&#xff0c;编译成exe文件&#xff0c;然后用Java去调&#xff0c;居然卡住不运行了。如果双击这个exe程序&#xff0c;单独让它运行&#xff0c;是可以的&#xff0c;那么为什么用Java调用就不好…

java中iscontinue意思_Java 中return、continue和break的区别

写在前面&#xff1a;适合Java初学者&#xff0c;大神就别来了。今天同事突然问我return和break的区别&#xff0c;以前觉得随口都能说出来的东西&#xff0c;今天突然卡了&#xff0c;记得模模糊糊&#xff0c;只能说出个大概&#xff0c;所以这里做一个总结&#xff0c;还是那…

第13步 用户模块前端(Admin)

bootstrap 就不用谢css样式 了 都写好了 http://www.bootcss.com/ https://www.bootcdn.cn/ <meta charset"utf-8"> <!-- 防止网站在手机端看变形了 --> <meta name"viewPort" content"widthdevice-width,initial…

ASP.NET Core 静态文件及JS包管理器(npm, Bower)的使用

在 ASP.NET Core 中添加静态文件 虽然ASP.NET主要大都做着后端的事情&#xff0c;但前端的一些静态文件也是很重要的。在ASP.NET Core中要启用静态文件&#xff0c;需要Microsoft.AspNetCore.StaticFiles组件。可以通过Nuget添加&#xff0c;或者在project.json配置文件中添加&…

Java 正则表达式匹配模式[贪婪型、勉强型、占有型]

转载自 Java 正则表达式匹配模式[贪婪型、勉强型、占有型]Greediness&#xff08;贪婪型&#xff09;&#xff1a;最大匹配 X?、X*、X、X{n&#xff0c;} 是最大匹配。例如你要用 “<.>” 去匹配 “a<tr>aava </tr>abb”&#xff0c;也许你所期待的结果是想…

新闻发布项目——分页公共类(PageUitl )

package bdqn.newsManageServlet.Util; /*** 分页的类* author Administrator**/ public class PageUitl {private int pagesize;//页大小private int pageindex1;//页码private int recordCount;//总记录数private int totalPageCount;//总页数//计算总页数public int getTota…

java代码配置 mybatis_配置简介(MyBatis源码篇)

1 SqlSessionFactoryBuilder#上篇例子中&#xff0c;我们以SqlSessionFactoryBuilder去创建SqlSessionFactory, 那么&#xff0c;我们就先从SqlSessionFactoryBuilder入手&#xff0c; 咱们先看看源码是怎么实现的。SqlSessionFactoryBuilder源码片段&#xff1a;public class …

js 方法传递对象参数

js 方法传递对象参数 2017年12月06日 16:35:39 qq_26676207 阅读数&#xff1a;7696 版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 https://blog.csdn.net/qq_26676207/article/details/78732117 第一步&#xff1a; //通过JSON.stringify()方…

Java8中 Date和LocalDateTime的相互转换

转载自 Java8中 Date和LocalDateTime的相互转换一.在Java 8中将Date转换为LocalDateTime 方法1: 将Date转换为LocalDatetime&#xff0c;我们可以使用以下方法&#xff1a; 1.从日期获取ZonedDateTime并使用其方法toLocalDateTime&#xff08;&#xff09;获取LocalDateTime 2…

java 时分秒格式小时8_Java里得到00:00:00格式的时分秒的Timestamp

复制代码 代码如下:import java.sql.Timestamp;import java.text.SimpleDateFormat;import java.util.TimeZone;public class Test {public static void main(String[] args) {SimpleDateFormat sdf new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");long t System.cu…

免费开源的 .NET 分布式组件库 Exceptionless Foundatio

前言 在互联网时代&#xff0c;分布式应用、系统变得越来越多&#xff0c;我们在使用 .Net 技术构建分布式系统的时候&#xff0c;需要使用到一些组件或者是助手库来帮助我们提高生产力以及应用程序解耦&#xff0c;但是纵观.Net圈&#xff0c;能够符合要求的这样的组件并不是很…

Java 8 中 Date与LocalDateTime、LocalDate、LocalTime互转

转载自 Java 8 中 Date与LocalDateTime、LocalDate、LocalTime互转Java 8中 java.util.Date 类新增了两个方法&#xff0c;分别是from(Instant instant)和toInstant()方法 // Obtains an instance of Date from an Instant object. public static Date from(Instant instant) …

mysql 删除过期日志_【转】对mysql日志进行操作的总结包括 启用,过期自动删除 等...

近段时间一直在研究mysql的日志系统,在网上看了N多mysql日志操作的文章&#xff0c;但都过于零乱&#xff0c;为了让自己以后不再搞忘&#xff0c;特作出以下总结&#xff1a;1. 以前我错误的认为mysql的日志可以恢复到任何时间的状态&#xff0c;其实并不是这样&#xff0c;这…

vo listVO paggerHelper mapper使用原则

注意 列表页面就显示这张表就好了 pageHelper 用2个mapper没有问题 xxxlistVO就好了详情哪里在展示多张表 不用分页你想链接几张表都可以 xxxVO 所有VO不要包含子对象注意一般vo对象中不可以包含对象&#xff01;&#xff01;&#xff01;&#xff01;&#xff…

Visual Studio 2015 for Linux更好地支持Linux下的开发

Visual C for Linux扩展使Visual Studio 2015的用户可以在VS2015中编写C或者C代码&#xff0c;并将代码部署到基于Linux的系统中去编译和调试。源代码和项目文件通过SSH传输到远程机上&#xff0c;程序的输出将显示在Visual Studio上。 Microsoft的Marc Goodner分享了更多有关新…

Google浏览器截长图 不需要借助任何插件!!!

1打开“谷歌浏览器”&#xff0c;右键单击网页空白处&#xff0c;然后点击“检查”。 2打开“开发者模式”&#xff0c;按“Ctrlshiftp”。 3.在输入框中输入“cpture”。 4.出现的三个模式分别为“截取全屏”、“node模式”和“当前范围”&#xff0c;选择想要的模式。 5.…

tomcat7.0.42如何设置mysql数据库连接池

转载自 tomcat7.0.42如何设置mysql数据库连接池 如何在tomcat7.0.42中设置mysql数据库连接池????eclipse如何绑定tomcat??按网上教程总不成功!怎么办server.xml<Resource name"jdbc/test" auth"Container" type"javax.sql.DataSource"…

自包含 .NET Core应用程序

.NET 是完全开源的&#xff0c;而且 .NET Core 是一个您可以免费下载的开源与跨平台 framework。您可以到 http://dot.net 获取 Mac、Windows 与大多数的 Unix 系统的版本。还可以使用免费、跨平台的 Visual Studio Code&#xff0c;用VS code您就可以随时随地编写 C# 与 F#。 …