Implementation Code of SignalR-based message pushing and QR code scanning logon, and signalr message pushing code
1. Summary
I believe you will not be unfamiliar with the use of scan login. The combination of QR code and mobile phone has produced different application scenarios, and the application based on QR code is more extensive. To meet the needs of the combination of ios and android clients and web messaging platforms, A scan login Based on SinglarR message push mechanism is developed. This system involves the following knowledge points:
SignalR: http://signalr.net/this official site, ASP. NET SignalR is a library for ASP. NET developers, can simplify the process of developers adding real-time Web functionality to the application. The real-time Web function refers to a function that allows the server code to push content immediately when the connected client becomes available, rather than waiting for the server to wait for the client to request new data.
QR code: used QRCode class library, https://github.com/jeromeetienne/jquery-qrcode
MVC5: the development environment is based on MVC5
2. System Relationship Diagram
Before implementing this function, it is a bit difficult to decide whether or not to win.
It is difficult to start with everything. By searching for information and analyzing it by yourself: The system involves mobile clients, viewers, and servers to achieve scan login, that is, how the three work together. Use axure to draw the following diagram:
Collaboration between mobile clients, viewers, and servers
[M]: indicates the mobile terminal [B]: indicates the viewer (browser client) [S]: Server, message pushing, and scan authentication interface publisher
Steps:
Step 1: [B] Browse the logon page. Step 2 [S] generates a UUID and pushes it to B to generate a login QR code;
Step 3: [M] scan the QR code on the premise that [M] is logged on. Step 4 [M] parse the QR code to obtain the UUID;
Step 5: [M] Send UUID + login information to the server, step 6 [S] perform resolution authentication on UUID + login information, step 6 UUID authentication, do not pass authentication, then to the Step6-1 re-generate UUID loop Step 2 and the Step6-2 returned to [M] UUID authentication failure reason, Step6 authentication, Step6-2 to login information Authentication, Step 7 login information Authentication, failed Step7-3 re-generate UUID loop Step 2, if successful, the Step7-1 is pushed to B to jump to the home page.
3. SignalR cyclic message push
3.1 reference SignalR
Because VS15Preview4 is used, you can directly use Nuget visual management Tools for installation: Tools-> Nuget Package Manager-> Manage Nuget Packages for Solution ..., Open the following interface:
Enter SignalR under the Browser tab and query Microsoft. AspNet. SignalR.
/P>
Find the corresponding project, click the "Install" installation button to reference the relevant class library, and download the relevant js library from the application.
Knowledge about SignalR, you can go to the official http://www.asp.net/signalr for in-depth learning.
3.2 server SignalR implementation
The server must push the UUID to the client. It has important features for the unique identifier of the UUID: (1) there is a time limit, the scan code is valid within 120 seconds; (2) there is a certain state. The corresponding declaration cycle is: generate-> push-> Status judgment-> mobile terminal scan-> verify UUID-> Status judgment-> destroy and other processes.
The core code of the server will be implemented by a separate project:
3.2.1 Nofifier. cs notification class
This class will connect QRCodeHub and 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 Core Implementation of QRCodeHub. cs SignalR
Core code of SignalR:
Using Microsoft. aspNet. signalR; using System. threading. tasks; namespace TxSms. singalR {// <summary> // QR code push /// </summary> // [HubName ("qrcode")] public class QRCodeHub: hub {/// <summary> /// sending time interval to the client /// </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> /// send the UUID content of the QR code /// </summary> /// <param name = "uuid"> </param> public void SendQRCodeUUID (string uuid) {Clients. client (Context. connectionId ). sendQRCodeUUID (uuid);} // <summary> // Called when the connection CTS to this hub instance. /// </summary> /// <returns> A <see cref = "T: System. threading. tasks. task "/> </returns> public override Tas K 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: Microsof T. 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);} // <summ Ary> // 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 >/// reset the clock /// </summary> public void ResetTimer () {SessionTimer timer; if (SessionTimer. timers. tryGetValue (Context. connectionId, out timer) {timer. resetTimer ();} else {SessionTimer. startTimer (Context. connectionId );}} /// <summary> /// send a common message /// </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 client clock
For [B], an independent timer is generated to send messages at intervals of 1 s.
Using System; using System. collections. concurrent; using System. timers; namespace TxSms. singalR {public class SessionTimer: IDisposable {/// <summary> // store the Timer corresponding to the client /// </summary> public static readonly ConcurrentDictionary <string, SessionTimer> Timers; private readonly Timer _ timer; static SessionTimer () {Timers = new ConcurrentDictionary <string, SessionTimer> ();} /// <summary> /// constructor /// </s Ummary> // <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> // client connection Id /// </summary> public string ConnectionId {get; set ;}//< summary> /// start 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> /// stop Timer /// </summary> /// <param name = "connectionId"> </param> public static void StopTimer (string connectionId) {SessionTimer oldTimer; if (Timers. tryRemove (connectionId, out oldTimer) {oldTimer. dispose () ;}/// <summary> /// reset 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> /// send a message to the client /// </summary> private void MonitorElapsedTime () {Utility. clearexpi1_uid (); 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 basic configuration of Utility. cs
Meeting clock requirements and obtaining QRCode
Using TxSms. actions; namespace TxSms. singalR {internal class Utility {public static int IntNum = 0; /// <summary> /// time interval /// </summary> /// <returns> </returns> public static int TimerValue () {return 1000 ;} public static double ActivityTimerInterval () {return 1000.0 ;} /// <summary> /// obtain the current 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> // Delete expired UUID /// </summary> public static void ClearExpiredUUID () {IntNum ++; if (IntNum <= 1000) return; new QRCodeAction (). clearexpi1_uid (); IntNum = 0 ;}}}
3.2.5 configure SignalR in MVC
In MVC, the startup project is configured as follows:
Using Microsoft. owin; using Owin; [assembly: OwinStartup (typeof (TxSms. web. startup)] namespace TxSms. web {public partial class Startup {public void Configuration (IAppBuilder app) {// start SignalR app. mapSignalR (); ConfigureAuth (app );}}}
3.2.6 other Class Libraries
QRCodeAction. cs: maintain UUID, create, save, change status, delete, and so on.
QRModel. cs: UUID entity
All files can be downloaded in summary and download.
3.3 client SignalR implementation
Add the SignalR js Library:
<script type="text/javascript" src="~/Scripts/jquery.signalR-2.2.1.min.js"></script> <script type="text/javascript" src="~/signalr/hubs"></script
Both must be referenced.
The Calling Interface is as follows:
Var codeUUID = ""; $ (function () {// Reference the auto-generated proxy for the hub. var qrcode = $. connection. qRCodeHub; // Create a function that the hub can call back to display messages. qrcode. client. addNewMessageToPage = function (name, message) {// Add the message to the page. console. log (message); // jQuery ('# divqrcode '). qrcode ({width: 180, height: 180, correctLevel: 0, text: message }); }; Qrcode. client. sendElapsedTime = function (time) {console. log (time) ;}; qrcode. client. sendQRCodeUUID = function (uuid) {console. log ("sendQRCodeUUID"); console. log (codeUUID); if (codeUUID = uuid) {return;} codeUUID = uuid; if (codeUUID! = "ERROR") {var jsonUUID = $. parseJSON (codeUUID); if (jsonUUID. islogin === 1) {// determine whether to log on to the window. location. href = "/Home/Index/@ Model. name ";}}$ (" # divQRCode ").html (" "); $ ('# divQRCode '). qrcode ({width: 180, height: 180, correctLevel: 0, text: codeUUID}) ;}; // Start the connection. $. connection. hub. start (). done (function () {// qrcode. server. updateConnectionId ($. connection. hub. id); qrcode. server. send ("qrcode", Math. random ());});});
The above Code includes the generation of the relevant QR code.
4. QR code generation and storage data parsing
4.1 generate a QR code
Two-dimensional code library selected https://github.com/jeromeetienne/jquery-qrcode A QRCode original js class library, jquery extended its.
Add the script Tag:
<script type="text/javascript" src="~/Scripts/qrcode.min.js"></script> <script type="text/javascript" src="~/Scripts/jquery.qrcode.min.js"></script>
Define the div tag to present the QR code:
<! -- QR code logon start --> <div> secure logon prevents theft </div> <div> scan logon </div>/ div> <! -- QR code logon ended -->
Display QR code:
$("#divQRCode").html(""); $('#divQRCode').qrcode({ width: 180, height: 180, correctLevel: 0, text: codeUUID });
Through 3 and 4, you can generate a 180-Second Life Cycle QR code. For different viewers, the generated QR code is different. The effect is as follows:
4.2 what is the QR code stored?
The QR code is generated, but what is stored? First, let's look at the following two-dimensional:
Hbuilder Official Website
Qianniu computer client QR code logon Interface
Obviously, scanning the QR code on the two images will produce different results. Decoding of some QR codes can only be performed by corresponding clients; otherwise, strings are parsed by other tools.
In this system, the QR code stores a json object in the following format:
{"connectionid":"19c12e95-26d7-410c-8292-2a3afdd1a4da","uuid":"a04702df-6a52-4e1c-be8b-9b3dbeef4d72","islogin":0,"isvalid":1}
Connectionid: the id of the client's contact with SignalR, in the format of Guid
Uuid: a unique identifier generated by connectionid, in the format of Guidislogin: whether the current connectionid connection is logged on, 1-> indicates logon, 0-> not logged on to isvalid: whether the uuid corresponding to the current connectionid is valid. 1-> indicates valid, 0-> indicates invalid
After the mobile client scans, you can determine whether to send a request to the server based on these parameters. When scanning applications (such as scanning logon), messages must be transmitted based on business scenarios to generate the corresponding QR code, not limited to json objects and URLs.
To sum up, the QR code application scenarios, such:
5. Scan authentication Interface
To meet the requirements of [M] side scanning, submit UUID + User information for authentication and establish the QRCode API. The interface task is simple, that is, to determine the UUID validity, then determine the user information logon status, and change the UUID logon status.
5.1 input parameters
Using Abp. application. services. dto; using System. componentModel. dataAnnotations; namespace TxSms. inputs {// <summary> // QR code logon authentication /// </summary> [Serializable] public class QRCodeVerifyInput: IInputDto {// <summary> // constructor // </summary> public QRCodeVerifyInput () {ConnectionId = Guid. empty. toString (); UUID = Guid. empty; UserName = Password = "" ;}/// <summary> /// current session ID /// </summary> [DisplayFormat (ConvertEmptyStringToNull = false)] public string ConnectionId {get; set ;}/// <summary> /// Unique Identifier /// </summary> public Guid UUID {get; set ;} /// <summary> /// user account /// </summary> [DisplayFormat (ConvertEmptyStringToNull = false)] public string UserName {get; set ;} /// <summary> /// logon Password /// </summary> [DisplayFormat (ConvertEmptyStringToNull = false)] public string Password {get; set ;} /// <summary> /// Platform /// </summary> [DisplayFormat (ConvertEmptyStringToNull = false)] public string Platform {get; set ;}}}
5.2 output parameters
Using Abp. application. services. dto; using Newtonsoft. json; using System. componentModel. dataAnnotations; using System. web. mvc; using TxSms. MVC; namespace TxSms. outputs {// <summary> // output base class /// </summary> [ModelBinder (typeof (EmptyStringModelBinder)] public class TxSmsOutputDto: IOutputDto {/// <summary> /// constructor // </summary> public TxSmsOutputDto () {Result = 0; // The default value is 0, indicates the initial value or the correct Message = "" ;}/// <summary> /// error code /// </summary> [JsonProperty ("Result")] public int Result {get; set ;}/// <summary> /// error message /// </summary> [DisplayFormat (ConvertEmptyStringToNull = false)] [JsonProperty ("Message")] public string Message {get; set ;}}}
5.3 API
Using System; using System. threading. tasks; using System. web. http; using TxSms. actions; using TxSms. inputs; using TxSms. outputs; namespace TxSms {// <summary> // QR code interface /// </summary> public class QRCodeController: txSmsApiController {// <summary> // QR code logon authentication /// </summary> /// <returns> // 0: logon successful;-1: parameter Error-2: ConnectionId, UUID, UserName, Password cannot be blank-3: ConnectionId session id does not exist-4: UUID input error-5: UUID expired //-6: Current UUID logged on-7: logged on Account Disabled-8: logged on Account Deleted-9: logon password entered error-10: the Logon account does not exist // </returns> [AllowAnonymous] [HttpPost] public async Task <strong> QRCodeVerify ([FromBody] QRCodeVerifyInput model) {login result = new TxSmsOutputDto (); # region parameter verification if (model. isNull () {result. result =-1; result. message = "parameter error"; return result;} if (model. connectionId. isNullOrEmpty () | model. UUID. equals (Guid. empty) | model. UserName. isNullOrEmpty () | model. password. isNullOrEmpty () {result. result =-2; result. message = "ConnectionId, UUID, UserName, and Password cannot be blank"; return result ;}# endregion parameter verification # region validity judgment // verify ConnectionId legality if (QRCodeAction. QRCodeLists. containsKey (model. connectionId) {result. result =-3; result. message = "ConnectionId session id does not exist"; return result;} // verify the validity of UUID var findCode = QRCodeAction. QRCodeLi Sts [model. ConnectionId]; if (! Model. UUID. Equals (findCode. UUID) {result. Result =-4; result. Message = "UUID input error"; return result;} if (! FindCode. isValid () {result. result =-5; result. message = "UUID expired"; return result;} if (findCode. isLogin) {result. result =-6; result. message = "This UUID has been logged on"; return result ;}# determine the validity of endregion LoginUserNameInput loginParam = new LoginUserNameInput {UserName = model. userName, Password = model. password, Platform = model. platform}; LoginOutput loginResult = await new SessionController (). loginUserName (loginParam); switch (loginResult. result) {case-1: result. result =-7; result. message = "logged on Account Disabled"; break; case-2: result. result =-8; result. message = "The Logon account has been deleted"; break; case-3: result. result =-9; result. message = "Logon password input error"; break; case-4: result. result =-10; result. message = "Logon account does not exist"; break;} if (loginResult. result> 0) // log on successfully. The value is AccId {result. result = 0; findCode. isLogin = true; // change the logon status result. message = "successfully logged on" ;}return result ;}}}
6. troubleshooting
6.1 #16 answers
Can images be added to the QR code? In the text, how does one deal with M letters on an image on the QR code?
The first question is: store the stored image information in the QR code. Can I scan the QR code to identify it? This problem involves the storage capacity of the QR code. Theoretically, if the storage capacity of the QR code is large enough, you can serialize the image to 01 characters for storage and scan to identify it. But the QR code has different standards, and the data capacity varies with standards. It is recommended not to store pictures, details can see know almost, understand: http://www.zhihu.com/question/20387257
The M letter is an image from Shanghai. Interested friends can view the QR code: http://cli.im/
6.2 #17 answers
Q: The input parameters include the user name and password. Which one needs to be entered every time? Or by scanning the QR code? Which method is used to assign values to the username and password of the input parameter. I want to know which method is implemented by the landlord?
First, you need to understand the login scanning process. [M] scan the QR code to obtain only the unique identifier information of [B]. After scanning the QR code, [M] (provided that [M] must have been successfully logged on) Send the username, password, and UUID to [S] for a series of verification. To improve security, when [M] submits data, it encrypts the password with the md5 timestamp.
6.3 #23 answers
In this way, no random generation code is generated on the mobile phone end. encryption is stored on the mobile phone and uploaded to the backend of the server to generate a QR code with the QR code plus the time.
To scan and log on, you can understand the following question: why does the data submitted to the server after scanning the QR code meet the requirements of the current page? In this project, it is confirmed by the inherent communication connectionid of SignalR. The process you mentioned should be as follows:
In this flowchart, the steps in the solution are extended. in step 2, problems may occur. How can I push the UUID pushed by [M] to the [B] end you see? Obviously, there is no link. This method is not feasible.
7. Summary and download
The QR code is widely used. Remember to go to zhongshan park next to the Palace Museum in Beijing. There are also QR codes in the ancient trees. You can scan and view the associated information. The two-dimensional code is used to store limited information, but the limited information can be used to connect a large information system. The applications used are not breakthroughs in cutting-edge technologies, it is the transformation of the way we think about the problem and the change of the angle of thinking. Because the QR code is unique in information storage, it can be used in the following aspects:
- Information Acquisition (business cards, maps, Wi-Fi passwords, and materials)
- Website jump (jump to Weibo, mobile website, website)
- Advertisement push (users scan the code to directly browse the video and audio advertisements pushed by sellers)
- Mobile e-commerce (User scanning, Direct shopping orders on mobile phones)
- Anti-counterfeit tracing (users can scan the code to view the production site; at the same time, the backend can obtain the final consumption location) promotions (users can scan the code, download electronic coupons, and draw prizes)
- Member Management (users can obtain electronic member information and VIP services on their mobile phones)
- Mobile Payment (scan the QR code and complete the payment through the mobile phone channel provided by the bank or a third party)
Recently, the text message service platform has applied the QR code to the marketing management. Each business personnel has an independent promotion QR code. The customer can scan the QR code for text message testing, if you register as a member, you will be the immediate customer of the business personnel. You can view the preliminary idea of QR code application in the text message service.
Finally, upload SignalR-based message push and QR code login implementation to download the main file: signalrqrcode