.net core下驗證碼及二維碼登錄的實現
在上一篇[.net core下訪問控制層的實現]主要介紹了通過中間件實現邏輯層面的許可權控制,本篇主要介紹下在 .net core下如何生成驗證碼和二維碼。
生成驗證碼
驗證碼實現的邏輯比較簡單,生成一個隨機數的圖片,然後將隨機數保存至cookie中,用於客戶端校驗。
首先是寫個生成隨機數的方法,下面提供個簡單的生成演算法,不是特別嚴謹,但作為後台管理應用基本夠用了。
private static string RndNum(int VcodeNum){ //驗證碼可以顯示的字符集合 string Vchar = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,p" + ",q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,P,P,Q" + ",R,S,T,U,V,W,X,Y,Z"; string[] VcArray = Vchar.Split(new Char[] { , });//拆分成數組 string code = "";//產生的隨機數 int temp = -1;//記錄上次隨機數值,盡量避避免生產幾個一樣的隨機數 Random rand = new Random(); //採用一個簡單的演算法以保證生成隨機數的不同 for (int i = 1; i < VcodeNum + 1; i++) { if (temp != -1) { rand = new Random(i * temp * unchecked((int)DateTime.Now.Ticks));//初始化隨機類 } int t = rand.Next(61);//獲取隨機數 if (temp != -1 && temp == t) { return RndNum(VcodeNum);//如果獲取的隨機數重複,則遞歸調用 } temp = t;//把本次產生的隨機數記錄起來 code += VcArray[t];//隨機數的位數加一 } return code;}
然後根據隨機數生成圖片流:
public static MemoryStream Create(out string code, int numbers = 4){ code = RndNum(numbers); //Bitmap img = null; //Graphics g = null; MemoryStream ms = null; Random random = new Random(); //驗證碼顏色集合 Color[] c = { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple }; //驗證碼字體集合 string[] fonts = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "宋體" }; using (var img = new Bitmap((int)code.Length * 18, 32)) { using (var g = Graphics.FromImage(img)) { g.Clear(Color.White);//背景設為白色 //在隨機位置畫背景點 for (int i = 0; i < 100; i++) { int x = random.Next(img.Width); int y = random.Next(img.Height); g.DrawRectangle(new Pen(Color.LightGray, 0), x, y, 1, 1); } //驗證碼繪製在g中 for (int i = 0; i < code.Length; i++) { int cindex = random.Next(7);//隨機顏色索引值 int findex = random.Next(5);//隨機字體索引值 Font f = new Font(fonts[findex], 15, FontStyle.Bold);//字體 Brush b = new SolidBrush(c[cindex]);//顏色 int ii = 4; if ((i + 1) % 2 == 0)//控制驗證碼不在同一高度 { ii = 2; } g.DrawString(code.Substring(i, 1), f, b, 3 + (i * 12), ii);//繪製一個驗證字元 } ms = new MemoryStream();//生成內存流對象 img.Save(ms, ImageFormat.Jpeg);//將此圖像以Png圖像文件的格式保存到流中 } } return ms;}
最後將流輸出,同時將隨機數保存至cookie中:
/// <summary>/// 獲取圖形驗證碼/// </summary>/// <returns></returns>[HttpGet("VerifyCode")]public async Task GetVerifyCode(){ Response.ContentType = "image/jpeg"; using (var stream = VerifyCodeHelper.Create(out string code)) { var buffer = stream.ToArray(); // 將驗證碼的token放入cookie Response.Cookies.Append(VERFIY_CODE_TOKEN_COOKIE_NAME, await SecurityServices.GetVerifyCodeToken(code)); await Response.Body.WriteAsync(buffer, 0, buffer.Length); }}
這樣就基本實現了驗證碼的生成,可以看下效果,輸入對應的/VerifyCode
就能出現對應的驗證碼:
生成二維碼
在 .net core下生成二維碼需要引入QRCoder.dll
第三方組件,生成二維碼代碼就比較簡單了:
/// <summary>/// /// </summary>/// <param name="url">存儲內容</param>/// <param name="pixel">像素大小</param>/// <returns></returns>public static Bitmap GetQRCode(string url, int pixel){ QRCodeGenerator generator = new QRCodeGenerator(); QRCodeData codeData = generator.CreateQrCode(url, QRCodeGenerator.ECCLevel.M, true); QRCode qrcode = new QRCode(codeData); Bitmap qrImage = qrcode.GetGraphic(pixel); return qrImage;}
這樣就可以將對應的登錄地址放至二維碼,返回至客戶端了:
/// <summary>/// 獲取登錄二維碼/// </summary>/// <returns></returns>[HttpGet("qrcode")]public async Task GetQRCode(){ Response.ContentType = "image/jpeg"; // 生成一個token並放入redis string qrToken = await SecurityServices.GetQRToken(); var bitmap = QRCodeHelper.GetQRCode($"{domain}/Security/Login?token={qrToken}", 4); // 將二維碼回調標識輸出給cookie // 創建cookie Response.Cookies.Append(QRTOKEN_COOKIE_NAME, qrToken); bitmap.Save(Response.Body, ImageFormat.Jpeg);}
這樣輸入地址/qrcode
就能返回對應的二維碼啦。
二維碼登錄實現
前面已經生成二維碼給客戶端了,如何實現登錄呢,這裡服務端還得提供一個介面給到客戶端,用於二維碼登錄結果回調。
客戶端輪詢該介面,判斷對應的token是否存在對應的登錄記錄,若存在則告訴客戶端已經登錄,客戶端即可調轉至首頁了,若不存在,則等待。
當然你可以設置一個二維碼失效時間,當二維碼失效客戶端自動跳轉至賬號密碼登錄頁。
我們創建一個二維碼登錄結果回調服務:
/// <summary>/// 二維碼登錄結果回調/// </summary>/// <returns></returns>[HttpGet("qrresult")]public async Task<LoginResult> GetQRResult(){string qrToken = Request.Cookies[QRTOKEN_COOKIE_NAME];if (string.IsNullOrWhiteSpace(qrToken)){ return new LoginResult { Code = (int)LoginResultCode.InvalidAccess };}return await SecurityServices.QRResult(qrToken);}
服務到redis中去找對應的登錄記錄,如果有則返回登錄成功:
public static async Task<LoginResult> QRResult(string token){ long temp = await redis.IncAsync(token); if (temp <= 1) { return new LoginResult { Code = (int)LoginResultCode.QRCodeExpired }; } string sessionId = await redis.Get<string>($"{token}_1"); if (string.IsNullOrWhiteSpace(sessionId)) { return new LoginResult { Code = (int)LoginResultCode.QRCodeStandby }; } return new LoginResult { Code = (int)LoginResultCode.Succeed, SessionId = sessionId };}
這樣就基本實現了二維碼的登錄啦。
總結
本篇主要講驗證碼和二維碼的實現和思路說了下,在小項目中基本夠用,有興趣的小夥伴可以嘗試一下。
推薦閱讀:
※C++ 三斜杠注釋 是什麼意思?
※c/cpp 中從源代碼到可執行文件的過程,鏈接是必須的嗎?
※C++ 編程軟體有哪些推薦?有沒有比 vc 6 更好的?
※在取消同步的情況下,為什麼cin的速度比scanf快?
※[C++] 能否設計一個一般的計時函數?