本文和大家分享的是一個整合1:小寫拼音;2:大寫拼音;3:數字;4:漢字的驗證碼產生類。本章例子也會有一個mvc使用驗證碼校正的情境。具有一定的參考價值,下面跟著小編一起來看下吧
本次和大家分享的是一個整合1:小寫拼音 2:大寫拼音 3:數字 4:漢字的驗證碼產生類,從標題來看感覺很普通的樣子,沒錯的確很普通,只是這個驗證碼類產生的時候可以通過參數指定驗證碼返回格式的規則,更主要的是希望能給大家帶來一定的實用性,本章例子也會有一個mvc使用驗證碼校正的情境,希望大家能夠喜歡。
» 驗證碼產生流程圖
» 驗證碼產生池代碼的解析
» 把驗證代碼畫到圖片上
» mvc登入操作測實驗證碼正確性
下面一步一個腳印的來分享:
» 驗證碼產生流程圖
首先,咋們來看一下本次分享的驗證碼產生類的產生流程圖:
能看到此圖描述的編碼產生池對應的是幾個不同的編碼內容,這裡主要根據參數設定允許同時擷取不同編碼內容,從而到達文字,拼音,漢字組合而成驗證碼,具體規則設定由參數而定;
» 驗證碼產生池代碼的解析
首先,由上面流程圖分析的內容能看出,這個驗證碼產生池子需要並行擷取不同類型驗證碼資料,才能滿足組合的驗證碼,因此有了下面的代碼:
/// <summary> /// 建立驗證碼 /// </summary> /// <param name="codeType">1:小寫拼音 2:大寫拼音 3:數字 4:漢字</param> /// <returns></returns> public static string CreateCode(string codeType = "1|2|3|4") { var code = string.Empty; try { if (string.IsNullOrWhiteSpace(codeType) || codeType.IndexOf('|') < 0) { codeType = "1|2|3|4"; } var codeTypeArr = codeType.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); var strLen = codeTypeArr.Length; //任務 Task<string>[] taskArr = new Task<string>[strLen]; for (int i = 0; i < strLen; i++) { var val = codeTypeArr[i]; switch (val) { case "1": //小寫拼音 taskArr[i] = Task.Factory.StartNew<string>(() => { return GetPinYinOrUpper(false); }); break; case "2": //大寫拼音 taskArr[i] = Task.Factory.StartNew<string>(() => { return GetPinYinOrUpper(); }); break; case "3": //數字 taskArr[i] = Task.Factory.StartNew<string>(() => { return GetShuZi(); }); break; case "4": //漢字 taskArr[i] = Task.Factory.StartNew<string>(() => { return GetHanZi(); }); break; default: break; } } //等待完成 30s Task.WaitAll(taskArr, TimeSpan.FromSeconds(30)); foreach (var item in taskArr) { code += item.Result; } } catch (Exception ex) { code = "我愛祖國"; } return code; }
這裡繼續使用了關鍵字Task,來分發任務擷取不同的驗證碼內容,個人認為最主要的還是通過參數設定 string codeType = "1|2|3|4" ,來確定驗證碼的組合方式,這樣也達到了驗證碼格式的多樣性;
» 把驗證代碼畫到圖片上
首先,咋們要明確的是要吧文字畫在某個圖片上,那麼需要用到Graphics關鍵字,以此來建立畫布把咋們的驗證編碼畫到圖片上,這裡先上代碼:
/// <summary> /// 產生驗證碼圖片流 /// </summary> /// <param name="code">驗證碼文字</param> /// <returns>流</returns> public static byte[] CreateValidateCodeStream(string code = "我愛祖國", int fontSize = 18, int width = 0, int height = 0, string fontFamily = "華文楷體") { var bb = new byte[0]; //初始化畫布 var padding = 2; var len = code.Length; width = width <= 0 ? fontSize * 2 * (len - 1) + padding * 4 : width; height = height <= 0 ? fontSize * 2 : height; var image = new Bitmap(width, height); var g = Graphics.FromImage(image); try { var random = new Random(); //清空背景色 g.Clear(Color.White); //畫橫向中間幹擾線 var x1 = 0; var y1 = height / 2; var x2 = width; var y2 = y1; g.DrawLine(new Pen(Color.DarkRed), x1, y1, x2, y2); //字型 var font = new Font(fontFamily, fontSize, (FontStyle.Bold | FontStyle.Italic)); var brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1f, true); //畫文字 var stringFomart = new StringFormat(); //垂直置中 stringFomart.LineAlignment = StringAlignment.Center; //水平置中 stringFomart.Alignment = StringAlignment.Center; var rf = new Rectangle(Point.Empty, new Size(width, height)); g.DrawString(code, font, brush, rf, stringFomart); //畫圖片的前景幹擾點 for (int i = 0; i < 100; i++) { var x = random.Next(image.Width); var y = random.Next(image.Height); image.SetPixel(x, y, Color.FromArgb(random.Next())); } //畫圖片的邊框線 g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1); //儲存圖片流 var stream = new MemoryStream(); image.Save(stream, ImageFormat.Jpeg); //輸出圖片流 bb = stream.ToArray(); } catch (Exception ex) { } finally { g.Dispose(); image.Dispose(); } return bb; }
這個列出畫驗證碼圖片方法的關鍵點:
1. 圖片的高和寬度需要設定,這個根據不同頁面配置方式而定,所以這裡吧高和寬用作參數傳遞
2. 幹擾線:通常驗證碼圖片都以一兩條幹擾線,主要防止某些惡意使用者使用圖片識別軟體進行不正規破解請求,我這裡幹擾線只設定了橫向置中的一天直線代碼如: g.DrawLine(new Pen(Color.DarkRed), x1, y1, x2, y2);
3. 字型:一個好看的字型通常也一種使用者體驗,因此這雷根據需要參數傳遞字型;
4. 驗證代碼位於圖片縱橫向置中,這裡的關鍵代碼是:
var stringFomart = new StringFormat(); //垂直置中 stringFomart.LineAlignment = StringAlignment.Center; //水平置中 stringFomart.Alignment = StringAlignment.Center;
5. g.DrawString(code, font, brush, rf, stringFomart); 主要用來把文字畫到圖片上,這是最關鍵的地方
6. 咋們通常都是吧驗證碼弄成圖片流,而不是真的產生一個實體的驗證碼圖片儲存到伺服器上,不然這樣伺服器很快就會磁碟不足,所以
//儲存圖片流 var stream = new MemoryStream(); image.Save(stream, ImageFormat.Jpeg); //輸出圖片流 bb = stream.ToArray();
這句的重要性也不可忽視,主要就把畫的內容儲存到流中方便使用
7. 最後千萬不用忘了使用Dispose釋放畫布
» mvc登入操作測實驗證碼正確性
有了上面驗證碼產生類產生好的驗證碼圖片,那麼我們還需要測實驗證下正確性和效果;下面我們使用mvc架構來做測試,先建立一個驗證碼測試Action並產生對應試圖ValidCode.cshtml檔案,然後自訂幾個不同格式的驗證碼擷取Action,代碼如下:
public FileResult GetValidateCode() { //返回的驗證碼文字 var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code); return File(bb_code, "image/jpeg"); } public FileResult GetValidateCode01() { var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code, "1|2|3|4"); return File(bb_code, "image/jpeg"); } public FileResult GetValidateCode02() { var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code, "4|3|2|1"); return File(bb_code, "image/jpeg"); } public FileResult GetValidateCode03() { var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code, "2|2|2|2"); return File(bb_code, "image/jpeg"); } public FileResult GetValidateCode04() { var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code, "4|4|4|4"); return File(bb_code, "image/jpeg"); } public FileResult GetValidateCode05() { var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code, "1|1|1|1"); return File(bb_code, "image/jpeg"); }
感覺上幾乎一模一樣,只是對應的參數不一樣,這裡遵循的方法GetValidateCodeStream參數codeType格式是:為空白表示自由組合 1:小寫拼音 2:大寫拼音 3:數字 4:漢字;然後我們往試圖中填寫如下代碼:
<h2>神牛 - 驗證碼執行個體</h2><p class="container " id="appVue"> <table class="table table-bordered text-left"> <tbody> <tr> <td>全部隨機</td> <td> <img src="/home/GetValidateCode" src="/home/GetValidateCode" id="imgCode" /> <input type="text" name="code" placeholder="請輸入驗證碼" class="form-control" /> <button class="btn btn-default">登 錄</button> <span id="msg" style="color:red"></span> </td> </tr> <tr> <td>小寫|大寫|數字|漢字</td> <td><img src="/home/GetValidateCode01" src="/home/GetValidateCode01" /></td> </tr> <tr> <td>漢字|數字|大寫|小寫</td> <td><img src="/home/GetValidateCode02" src="/home/GetValidateCode02" /></td> </tr> <tr> <td>全部大寫</td> <td><img src="/home/GetValidateCode03" src="/home/GetValidateCode03" /></td> </tr> <tr> <td>全部漢字</td> <td><img src="/home/GetValidateCode04" src="/home/GetValidateCode04" /></td> </tr> <tr> <td>全部小寫</td> <td><img src="/home/GetValidateCode05" src="/home/GetValidateCode05" /></td> </tr> </tbody> </table></p>
好了咋們產生下項目,看下如下:
能看到我們驗證碼格式的不同之處,這也是文章開頭說的驗證碼格式的多樣性,當然可能還有其他組成格式請允許我暫時忽略,下面我們來做一個點擊圖片擷取新驗證碼的功能和點擊登入按鈕去背景程式判斷驗證碼是否匹配的例子,先來修改試圖介面代碼如下:
@{ ViewBag.Title = "ValidtCode";}<h2>神牛 - 驗證碼執行個體</h2><p class="container " id="appVue"> <table class="table table-bordered text-left"> <tbody> <tr> <td>全部隨機</td> <td> <img src="/home/GetValidateCode" src="/home/GetValidateCode" id="imgCode" /> <input type="text" name="code" placeholder="請輸入驗證碼" class="form-control" /> <button class="btn btn-default">登 錄</button> <span id="msg" style="color:red"></span> </td> </tr> <tr> <td>小寫|大寫|數字|漢字</td> <td><img src="/home/GetValidateCode01" src="/home/GetValidateCode01" /></td> </tr> <tr> <td>漢字|數字|大寫|小寫</td> <td><img src="/home/GetValidateCode02" src="/home/GetValidateCode02" /></td> </tr> <tr> <td>全部大寫</td> <td><img src="/home/GetValidateCode03" src="/home/GetValidateCode03" /></td> </tr> <tr> <td>全部漢字</td> <td><img src="/home/GetValidateCode04" src="/home/GetValidateCode04" /></td> </tr> <tr> <td>全部小寫</td> <td><img src="/home/GetValidateCode05" src="/home/GetValidateCode05" /></td> </tr> </tbody> </table></p><script src="~/Scripts/jquery-1.10.2.min.js"></script><script type="text/javascript"> $(function () { $("img").on("click", function () { var nowTime = new Date().getTime(); var src = $(this).attr("src") + "?t=" + nowTime; if (src.length <= 0) { return; } $(this).attr("src", src); }); $("button").on("click", function () { var msg = $("#msg"); var code = $("input[name='code']").val(); if (code.length <= 0) { msg.html("請輸入驗證碼!"); return; } $.post("/home/UserLogin", { code: code }, function (result) { if (result) { msg.html(result.Msg); if (!result.IsOk) { $("#imgCode").click(); } } }); }) })</script>
然後在Controller中增加如下登入驗證代碼:
public JsonResult UserLogin(string code) { var data = new Stage.Com.Extend.StageModel.MoData(); if (string.IsNullOrWhiteSpace(code)) { data.Msg = "驗證碼不可為空"; return Json(data); } var compareCode = Session["code"]; if (!compareCode.Equals(code)) { data.Msg = "驗證碼錯誤"; return Json(data); } data.IsOk = true; data.Msg = "驗證碼驗證成功"; return Json(data); } public FileResult GetValidateCode() { //返回的驗證碼文字 var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code); var key = "code"; if (Session[key] != null) { Session.Remove(key); } Session[key] = code; return File(bb_code, "image/jpeg"); }
由於我這裡無法截動態圖,所點擊測試擷取驗證碼我這裡直接給出線上的一個例子,各位可以試試:http://lovexins.com:1001/home/ValidCode,點擊擷取新驗證碼的關鍵代碼是: $(this).attr("src", src); 重新給img元素的scr賦值,不過這裡要注意由於瀏覽器緩衝的原因,這裡賦值的時候需要加上一個動態參數,我這裡是使用時間作為請求參數,因此有了以下的代碼: $(this).attr("src") + "?t=" + nowTime; 這是特別的地方需要注意;好了咋們來直接測試登陸是否能從後端判斷驗證碼是否正確匹配吧,這裡用的是session來儲存擷取驗證碼圖片返回的驗證代碼,然後在登陸時候判斷使用者資料的驗證碼是否和後台session的驗證一樣:
驗證失敗:
驗證成功:
好了測試案例就這麼多,如果您覺得我這個驗證碼產生例子還可以並且您希望使用那麼請注意,參數的傳遞,不同得到的驗證碼格式不同,主要方法是:
/// <summary> /// 擷取驗證碼圖片流 /// </summary> /// <param name="codeLen">驗證碼個數(codeType設定 > codeLen設定)</param> /// <param name="codeType">為空白表示自由組合 1:小寫拼音 2:大寫拼音 3:數字 4:漢字</param> /// <returns></returns> public static byte[] GetValidateCodeStream(ref string code, string codeType = "", int codeLen = 0, int fontSize = 18, int width = 120, int height = 30) { //為空白自由組合 if (string.IsNullOrWhiteSpace(codeType)) { for (int i = 0; i < codeLen; i++) { codeType += rm.Next(1, 5) + "|"; } } code = CreateCode(codeType); return CreateValidateCodeStream(code, fontSize, width: width, height: height); }
具體參數各位可以看下備忘,我這裡順便打包下代碼,方便分享和使用:驗證碼產生樣本