您现在的位置是:网站首页> 编程资料编程资料

基于SignalR的消息推送与二维码扫描登录实现代码_实用技巧_

2023-05-24 555人已围观

简介 基于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

/p>

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

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

3.2 服务端SignalR实现

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

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

3.2.1 Nofifier.cs通知类

本类将连接QRCodeHub与SessionTimer

 using Microsoft.AspNet.SignalR;namespace TxSms.SingalR { public static class Notifier { private static readonly IHubContext Context = GlobalHost.ConnectionManager.GetHubContext(); public static void SessionTimeOut(string connectionId, int time) { Context.Clients.Client(connectionId).alertClient(time); } public static void SendElapsedTime(string connectionId, int time) { Context.Clients.Client(connectionId).sendElapsedTime(time); } public static void SendQRCodeUUID(string connectionId, string uuid) { Context.Clients.Client(connectionId).sendQRCodeUUID(uuid); } } }

3.2.2 QRCodeHub.cs SignalR核心实现

SignalR的核心代码:

 using Microsoft.AspNet.SignalR; using System.Threading.Tasks; namespace TxSms.SingalR { ///  /// 二维码推送 ///  //[HubName("qrcode")] public class QRCodeHub : Hub { ///  /// 给客户端发送时间间隔 ///  ///  public void SendTimeOutNotice(int time) { Clients.Client(Context.ConnectionId).alertClient(time); } public void CheckElapsedTime(int time) { Clients.Client(Context.ConnectionId).sendElapsedTime(time); } ///  /// 发送二维码UUID内容 ///  ///  public void SendQRCodeUUID(string uuid) { Clients.Client(Context.ConnectionId).sendQRCodeUUID(uuid); } ///  /// Called when the connection connects to this hub instance. ///  /// A  public override Task OnConnected() { SessionTimer.StartTimer(Context.ConnectionId); return base.OnConnected(); } ///  /// Called when a connection disconnects from this hub gracefully or due to a timeout. ///  ///  /// true, if stop was called on the client closing the connection gracefully; /// false, if the connection has been lost for longer than the /// . /// Timeouts can be caused by clients reconnecting to another SignalR server in scaleout. ///  /// A  public override Task OnDisconnected(bool stopCalled) { SessionTimer.StopTimer(Context.ConnectionId); return base.OnDisconnected(stopCalled); } ///  /// Called when the connection reconnects to this hub instance. ///  /// A  public override Task OnReconnected() { if (!SessionTimer.Timers.ContainsKey(Context.ConnectionId)) { SessionTimer.StartTimer(Context.ConnectionId); } return base.OnReconnected(); } ///  /// 重置时钟 ///  public void ResetTimer() { SessionTimer timer; if (SessionTimer.Timers.TryGetValue(Context.ConnectionId, out timer)) { timer.ResetTimer(); } else { SessionTimer.StartTimer(Context.ConnectionId); } } ///  /// 发送普通消息 ///  ///  ///  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 { ///  /// 存储客户端对应的Timer ///  public static readonly ConcurrentDictionary Timers; private readonly Timer _timer; static SessionTimer() { Timers = new ConcurrentDictionary(); } ///  /// 构造函数 ///  ///  private SessionTimer(string connectionId) { ConnectionId = connectionId; _timer = new Timer { Interval = Utility.ActivityTimerInterval() }; _timer.Elapsed += (s, e) => MonitorElapsedTime(); _timer.Start(); } public int TimeCount { get; set; } ///  /// 客户端连接Id ///  public string ConnectionId { get; set; } ///  /// 启动Timer ///  ///  public static void StartTimer(string connectionId) { var newTimer = new SessionTimer(connectionId); if (!Timers.TryAdd(connectionId, newTimer)) { newTimer.Dispose(); } } ///  /// 停止Timer ///  ///  public static void StopTimer(string connectionId) { SessionTimer oldTimer; if (Timers.TryRemove(connectionId, out oldTimer)) { oldTimer.Dispose(); } } ///  /// 重置Timer ///  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(); } ///  /// 给客户端发送消息 ///  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; ///  /// 时间间隔 ///  ///  public static int TimerValue() { return 1000; } public static double ActivityTimerInterval() { return 1000.0; } ///  /// 获取当前UUID ///  ///  public static string GetUUID(string connectionId) { try { var model = new QRCodeAction().GetValidModel(connectionId); return model.ToJson(connectionId); } catch { return "ERROR"; } } ///  /// 删除过期UUID ///  public static void ClearExpiredUUID() { IntNum++; if (IntNum <= 1000) return; new QRCodeAction().ClearExpiredUUID(); IntNum = 0; } }}

3.2.5 SignalR在MVC中启动配置

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

 using Microsoft.Owin;using Owin; [assembly: OwinStartup(typeof(TxSms.Web.Startup))]namespace TxSms.Web{ public partial class Startup { public void Configuration(IAppBuilder app) { //启动SignalR app.MapSignalR(); ConfigureAuth(app); } }}

3.2.6 其他类库说明

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

QRModel.cs:UUID实体

所有文件,可在《7、总结与下载》中下载。

3.3 客户端SignalR实现

添加SignalR js库: