本次和大家分享的是一個集成1:小寫拼音 2:大寫拼音 3:數(shù)字 4:漢字的驗證碼生成類,從標題來看感覺很普通的樣子,沒錯的確很普通,只是這個驗證碼類生成的時候可以通過參數(shù)指定驗證碼返回格式的規(guī)則,更主要的是希望能給大家?guī)硪欢ǖ膶嵱眯裕菊吕右矔幸粋€mvc使用驗證碼校驗的場景,希望大家能夠喜歡。
» 驗證碼生成流程圖
» 驗證碼生成池代碼的解析
» 把驗證代碼畫到圖片上
» mvc登錄操作測試驗證碼正確性
下面一步一個腳印的來分享:
» 驗證碼生成流程圖
首先,咋們來看一下本次分享的驗證碼生成類的生成流程圖:
能看到此圖描述的編碼生成池對應(yīng)的是幾個不同的編碼內(nèi)容,這里主要根據(jù)參數(shù)設(shè)置允許同時獲取不同編碼內(nèi)容,從而到達文字,拼音,漢字組合而成驗證碼,具體規(guī)則設(shè)置由參數(shù)而定;
» 驗證碼生成池代碼的解析
首先,由上面流程圖分析的內(nèi)容能看出,這個驗證碼生成池子需要并行獲取不同類型驗證碼數(shù)據(jù),才能滿足組合的驗證碼,因此有了下面的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
/// <summary> /// 創(chuàng)建驗證碼 /// </summary> /// <param name="codeType">1:小寫拼音 2:大寫拼音 3:數(shù)字 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; //任務(wù) 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" : //數(shù)字 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; } |
這里繼續(xù)使用了關(guān)鍵字Task,來分發(fā)任務(wù)獲取不同的驗證碼內(nèi)容,個人認為最主要的還是通過參數(shù)設(shè)置 string codeType = "1|2|3|4" ,來確定驗證碼的組合方式,這樣也達到了驗證碼格式的多樣性;
» 把驗證代碼畫到圖片上
首先,咋們要明確的是要吧文字畫在某個圖片上,那么需要用到Graphics關(guān)鍵字,以此來創(chuàng)建畫布把咋們的驗證編碼畫到圖片上,這里先上代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
/// <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; } |
這個列出畫驗證碼圖片方法的關(guān)鍵點:
1. 圖片的高和寬度需要設(shè)置,這個根據(jù)不同頁面布局方式而定,所以這里吧高和寬用作參數(shù)傳遞
2. 干擾線:通常驗證碼圖片都以一兩條干擾線,主要防止某些惡意用戶使用圖片識別軟件進行不正規(guī)破解請求,我這里干擾線只設(shè)置了橫向居中的一天直線代碼如: g.DrawLine(new Pen(Color.DarkRed), x1, y1, x2, y2);
3. 字體:一個好看的字體通常也一種用戶體驗,因此這里根據(jù)需要參數(shù)傳遞字體;
4. 驗證代碼位于圖片縱橫向居中,這里的關(guān)鍵代碼是:
1
2
3
4
5
|
var stringFomart = new StringFormat(); //垂直居中 stringFomart.LineAlignment = StringAlignment.Center; //水平居中 stringFomart.Alignment = StringAlignment.Center; |
5. g.DrawString(code, font, brush, rf, stringFomart); 主要用來把文字畫到圖片上,這是最關(guān)鍵的地方
6. 咋們通常都是吧驗證碼弄成圖片流,而不是真的生成一個實體的驗證碼圖片保存到服務(wù)器上,不然這樣服務(wù)器很快就會磁盤不足,所以
1
2
3
4
5
|
//保存圖片流 var stream = new MemoryStream(); image.Save(stream, ImageFormat.Jpeg); //輸出圖片流 bb = stream.ToArray(); |
這句的重要性也不可忽視,主要就把畫的內(nèi)容保存到流中方便使用
7. 最后千萬不用忘了使用Dispose釋放畫布
» mvc登錄操作測試驗證碼正確性
有了上面驗證碼生成類生成好的驗證碼圖片,那么我們還需要測試驗證下正確性和效果;下面我們使用mvc架構(gòu)來做測試,先創(chuàng)建一個驗證碼測試Action并生成對應(yīng)試圖ValidCode.cshtml文件,然后自定義幾個不同格式的驗證碼獲取Action,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
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" ); } |
感覺上幾乎一模一樣,只是對應(yīng)的參數(shù)不一樣,這里遵循的方法GetValidateCodeStream參數(shù)codeType格式是:為空表示自由組合 1:小寫拼音 2:大寫拼音 3:數(shù)字 4:漢字;然后我們往試圖中填寫如下代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
< h2 >神牛 - 驗證碼實例</ h2 > < div class = "container " id = "appVue" > < table class = "table table-bordered text-left" > < tbody > < tr > < td >全部隨機</ td > < td > < img src = "/home/GetValidateCode" data-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 >小寫|大寫|數(shù)字|漢字</ td > < td >< img src = "/home/GetValidateCode01" data-src = "/home/GetValidateCode01" /></ td > </ tr > < tr > < td >漢字|數(shù)字|大寫|小寫</ td > < td >< img src = "/home/GetValidateCode02" data-src = "/home/GetValidateCode02" /></ td > </ tr > < tr > < td >全部大寫</ td > < td >< img src = "/home/GetValidateCode03" data-src = "/home/GetValidateCode03" /></ td > </ tr > < tr > < td >全部漢字</ td > < td >< img src = "/home/GetValidateCode04" data-src = "/home/GetValidateCode04" /></ td > </ tr > < tr > < td >全部小寫</ td > < td >< img src = "/home/GetValidateCode05" data-src = "/home/GetValidateCode05" /></ td > </ tr > </ tbody > </ table > </ div > |
好了咋們生成下項目,看下效果圖如下:
能從圖中看到我們驗證碼格式的不同之處,這也是文章開頭說的驗證碼格式的多樣性,當然可能還有其他組成格式請允許我暫時忽略,下面我們來做一個點擊圖片獲取新驗證碼的功能和點擊登錄按鈕去后臺程序判斷驗證碼是否匹配的例子,先來修改試圖界面代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
@{ ViewBag.Title = "ValidtCode"; } < h2 >神牛 - 驗證碼實例</ h2 > < div class = "container " id = "appVue" > < table class = "table table-bordered text-left" > < tbody > < tr > < td >全部隨機</ td > < td > < img src = "/home/GetValidateCode" data-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 >小寫|大寫|數(shù)字|漢字</ td > < td >< img src = "/home/GetValidateCode01" data-src = "/home/GetValidateCode01" /></ td > </ tr > < tr > < td >漢字|數(shù)字|大寫|小寫</ td > < td >< img src = "/home/GetValidateCode02" data-src = "/home/GetValidateCode02" /></ td > </ tr > < tr > < td >全部大寫</ td > < td >< img src = "/home/GetValidateCode03" data-src = "/home/GetValidateCode03" /></ td > </ tr > < tr > < td >全部漢字</ td > < td >< img src = "/home/GetValidateCode04" data-src = "/home/GetValidateCode04" /></ td > </ tr > < tr > < td >全部小寫</ td > < td >< img src = "/home/GetValidateCode05" data-src = "/home/GetValidateCode05" /></ td > </ tr > </ tbody > </ table > </ div > < 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("data-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中增加如下登錄驗證代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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" ); } |
由于我這里無法截動態(tài)圖,所點擊測試獲取驗證碼我這里直接給出線上的一個例子,各位可以試試:http://lovexins.com:1001/home/ValidCode,點擊獲取新驗證碼的關(guān)鍵代碼是: $(this).attr("src", src); 重新給img元素的scr賦值,不過這里要注意由于瀏覽器緩存的原因,這里賦值的時候需要加上一個動態(tài)參數(shù),我這里是使用時間作為請求參數(shù),因此有了以下的代碼: $(this).attr("data-src") + "?t=" + nowTime; 這是特別的地方需要注意;好了咋們來直接測試登陸是否能從后端判斷驗證碼是否正確匹配吧,這里用的是session來保存獲取驗證碼圖片返回的驗證代碼,然后在登陸時候判斷用戶數(shù)據(jù)的驗證碼是否和后臺session的驗證一樣:
驗證失敗:
驗證成功:
好了測試用例就這么多,如果您覺得我這個驗證碼生成例子還可以并且您希望使用那么請注意,參數(shù)的傳遞,不同得到的驗證碼格式不同,主要方法是:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/// <summary> /// 獲取驗證碼圖片流 /// </summary> /// <param name="codeLen">驗證碼個數(shù)(codeType設(shè)置 > codeLen設(shè)置)</param> /// <param name="codeType">為空表示自由組合 1:小寫拼音 2:大寫拼音 3:數(shù)字 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); } |
具體參數(shù)各位可以看下備注,我這里順便打包下代碼,方便分享和使用:驗證碼生成示例
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時也希望多多支持服務(wù)器之家!
原文鏈接:http://www.cnblogs.com/wangrudong003/p/6279647.html