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

网络编程 2021-07-04 22:41www.168986.cn编程入门
这篇文章主要介绍了基于SignalR的消息推送与二维码扫描登录实现代码,需要的朋友可以参考下

1 概要说明

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

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

二维码:使用的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的知识点,可以到官网 进行深入学习。

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<QRCodeHub>(); 
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
{ 
/// <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="sCalled">
/// true, if s 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 sCalled) { SessionTimer.STimer(Context.ConnectionId); return base.OnDisconnected(sCalled);
} 
/// <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 STimer(string connectionId) 
{
SessionTimer oldTimer; 
if (Timers.TryRemove(connectionId, out oldTimer))
{ 
oldTimer.Dispose();
} 
} 
/// <summary> /// 
重置Timer /// 
</summary> public void ResetTimer() { TimeCount = 0; _timer.S();
_timer.Start(); 
} 
public void Dispose()
{ 
// S might not be necessary since we call Dispose _timer.S(); _timer.Dispose(); 
} ///

<summary> ///
给客户端发送消息 /// 
</summary> private void MonitorElapsedTime() 
{ Utility.ClearExpiredUUID(); var uuid = Utility.GetUUID(ConnectionId); 
//if (TimeCount >= Utility.TimerValue()) 
//{ // STimer(ConnectionId);
// Notifier.SendQRCodeUUID(ConnectionId, uuid); // Notifier.SessionTimeOut(ConnectionId, TimeCount); 
/ 

Copyright © 2016-2025 www.168986.cn 狼蚁网络 版权所有 Power by