溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

.net如何封裝一個(gè)驗(yàn)證碼生成類

發(fā)布時(shí)間:2020-07-13 14:03:52 來(lái)源:億速云 閱讀:204 作者:Leah 欄目:編程語(yǔ)言

.net如何封裝一個(gè)驗(yàn)證碼生成類?很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。

本次和大家分享的是一個(gè)集成1:小寫拼音 2:大寫拼音 3:數(shù)字 4:漢字的驗(yàn)證碼生成類,從標(biāo)題來(lái)看感覺(jué)很普通的樣子,沒(méi)錯(cuò)的確很普通,只是這個(gè)驗(yàn)證碼類生成的時(shí)候可以通過(guò)參數(shù)指定驗(yàn)證碼返回格式的規(guī)則,更主要的是希望能給大家?guī)?lái)一定的實(shí)用性,本章例子也會(huì)有一個(gè)mvc使用驗(yàn)證碼校驗(yàn)的場(chǎng)景,希望大家能夠喜歡。

? 驗(yàn)證碼生成流程圖

? 驗(yàn)證碼生成池代碼的解析

? 把驗(yàn)證代碼畫到圖片上

? mvc登錄操作測(cè)試驗(yàn)證碼正確性

下面一步一個(gè)腳印的來(lái)分享:

? 驗(yàn)證碼生成流程圖

首先,咋們來(lái)看一下本次分享的驗(yàn)證碼生成類的生成流程圖:

.net如何封裝一個(gè)驗(yàn)證碼生成類

能看到此圖描述的編碼生成池對(duì)應(yīng)的是幾個(gè)不同的編碼內(nèi)容,這里主要根據(jù)參數(shù)設(shè)置允許同時(shí)獲取不同編碼內(nèi)容,從而到達(dá)文字,拼音,漢字組合而成驗(yàn)證碼,具體規(guī)則設(shè)置由參數(shù)而定;

? 驗(yàn)證碼生成池代碼的解析

首先,由上面流程圖分析的內(nèi)容能看出,這個(gè)驗(yàn)證碼生成池子需要并行獲取不同類型驗(yàn)證碼數(shù)據(jù),才能滿足組合的驗(yàn)證碼,因此有了下面的代碼:

/// <summary>
 /// 創(chuàng)建驗(yàn)證碼
 /// </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 = "我愛(ài)祖國(guó)";
 }
 return code;
 }

這里繼續(xù)使用了關(guān)鍵字Task,來(lái)分發(fā)任務(wù)獲取不同的驗(yàn)證碼內(nèi)容,個(gè)人認(rèn)為最主要的還是通過(guò)參數(shù)設(shè)置 string codeType = "1|2|3|4" ,來(lái)確定驗(yàn)證碼的組合方式,這樣也達(dá)到了驗(yàn)證碼格式的多樣性;

? 把驗(yàn)證代碼畫到圖片上

首先,咋們要明確的是要吧文字畫在某個(gè)圖片上,那么需要用到Graphics關(guān)鍵字,以此來(lái)創(chuàng)建畫布把咋們的驗(yàn)證編碼畫到圖片上,這里先上代碼:

/// <summary>
 /// 生成驗(yàn)證碼圖片流
 /// </summary>
 /// <param name="code">驗(yàn)證碼文字</param>
 /// <returns>流</returns>
 public static byte[] CreateValidateCodeStream(string code = "我愛(ài)祖國(guó)", 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);
 //畫圖片的前景干擾點(diǎn)
 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;
 }

這個(gè)列出畫驗(yàn)證碼圖片方法的關(guān)鍵點(diǎn):

1. 圖片的高和寬度需要設(shè)置,這個(gè)根據(jù)不同頁(yè)面布局方式而定,所以這里吧高和寬用作參數(shù)傳遞

2. 干擾線:通常驗(yàn)證碼圖片都以一兩條干擾線,主要防止某些惡意用戶使用圖片識(shí)別軟件進(jìn)行不正規(guī)破解請(qǐng)求,我這里干擾線只設(shè)置了橫向居中的一天直線代碼如: g.DrawLine(new Pen(Color.DarkRed), x1, y1, x2, y2);

3. 字體:一個(gè)好看的字體通常也一種用戶體驗(yàn),因此這里根據(jù)需要參數(shù)傳遞字體;

4. 驗(yàn)證代碼位于圖片縱橫向居中,這里的關(guān)鍵代碼是:

 var stringFomart = new StringFormat();
 //垂直居中
 stringFomart.LineAlignment = StringAlignment.Center;
 //水平居中
 stringFomart.Alignment = StringAlignment.Center;

5.   g.DrawString(code, font, brush, rf, stringFomart); 主要用來(lái)把文字畫到圖片上,這是最關(guān)鍵的地方

6. 咋們通常都是吧驗(yàn)證碼弄成圖片流,而不是真的生成一個(gè)實(shí)體的驗(yàn)證碼圖片保存到服務(wù)器上,不然這樣服務(wù)器很快就會(huì)磁盤不足,所以

 //保存圖片流
 var stream = new MemoryStream();
 image.Save(stream, ImageFormat.Jpeg);
 //輸出圖片流
 bb = stream.ToArray();

這句的重要性也不可忽視,主要就把畫的內(nèi)容保存到流中方便使用

7. 最后千萬(wàn)不用忘了使用Dispose釋放畫布

? mvc登錄操作測(cè)試驗(yàn)證碼正確性

有了上面驗(yàn)證碼生成類生成好的驗(yàn)證碼圖片,那么我們還需要測(cè)試驗(yàn)證下正確性和效果;下面我們使用mvc架構(gòu)來(lái)做測(cè)試,先創(chuàng)建一個(gè)驗(yàn)證碼測(cè)試Action并生成對(duì)應(yīng)試圖ValidCode.cshtml文件,然后自定義幾個(gè)不同格式的驗(yàn)證碼獲取Action,代碼如下:

public FileResult GetValidateCode()
 {
 //返回的驗(yàn)證碼文字
 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");
 }

感覺(jué)上幾乎一模一樣,只是對(duì)應(yīng)的參數(shù)不一樣,這里遵循的方法GetValidateCodeStream參數(shù)codeType格式是:為空表示自由組合  1:小寫拼音 2:大寫拼音 3:數(shù)字 4:漢字;然后我們往試圖中填寫如下代碼:

<h3>神牛 - 驗(yàn)證碼實(shí)例</h3>
<p class="container " id="appVue">
 <table class="table table-bordered text-left">
 <tbody>
 <tr>
 <td>全部隨機(jī)</td>
 <td>
  <img src="/home/GetValidateCode" src="/home/GetValidateCode" id="imgCode" />
  <input type="text" name="code" placeholder="請(qǐng)輸入驗(yàn)證碼" 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" src="/home/GetValidateCode01" /></td>
 </tr>
 <tr>
 <td>漢字|數(shù)字|大寫|小寫</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>

好了咋們生成下項(xiàng)目,看下效果圖如下:

.net如何封裝一個(gè)驗(yàn)證碼生成類

能從圖中看到我們驗(yàn)證碼格式的不同之處,這也是文章開(kāi)頭說(shuō)的驗(yàn)證碼格式的多樣性,當(dāng)然可能還有其他組成格式請(qǐng)?jiān)试S我暫時(shí)忽略,下面我們來(lái)做一個(gè)點(diǎn)擊圖片獲取新驗(yàn)證碼的功能和點(diǎn)擊登錄按鈕去后臺(tái)程序判斷驗(yàn)證碼是否匹配的例子,先來(lái)修改試圖界面代碼如下:

@{
 ViewBag.Title = "ValidtCode";
}
<h3>神牛 - 驗(yàn)證碼實(shí)例</h3>
<p class="container " id="appVue">
 <table class="table table-bordered text-left">
 <tbody>
 <tr>
 <td>全部隨機(jī)</td>
 <td>
  <img src="/home/GetValidateCode" src="/home/GetValidateCode" id="imgCode" />
  <input type="text" name="code" placeholder="請(qǐng)輸入驗(yàn)證碼" 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" src="/home/GetValidateCode01" /></td>
 </tr>
 <tr>
 <td>漢字|數(shù)字|大寫|小寫</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("請(qǐng)輸入驗(yàn)證碼!"); return; }

 $.post("/home/UserLogin", { code: code }, function (result) {
 if (result) {
  msg.html(result.Msg);
  if (!result.IsOk) {
  $("#imgCode").click();
  }
 }
 });
 })
 })
</script>

然后在Controller中增加如下登錄驗(yàn)證代碼:

public JsonResult UserLogin(string code)
 {
 var data = new Stage.Com.Extend.StageModel.MoData();
 if (string.IsNullOrWhiteSpace(code)) { data.Msg = "驗(yàn)證碼不能為空"; return Json(data); }
 var compareCode = Session["code"];
 if (!compareCode.Equals(code)) { data.Msg = "驗(yàn)證碼錯(cuò)誤"; return Json(data); }
 data.IsOk = true;
 data.Msg = "驗(yàn)證碼驗(yàn)證成功";
 return Json(data);
 }
 public FileResult GetValidateCode()
 {
 //返回的驗(yàn)證碼文字
 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");
 }

由于我這里無(wú)法截動(dòng)態(tài)圖,所點(diǎn)擊測(cè)試獲取驗(yàn)證碼我這里直接給出線上的一個(gè)例子,各位可以試試:http://lovexins.com:1001/home/ValidCode,點(diǎn)擊獲取新驗(yàn)證碼的關(guān)鍵代碼是:  $(this).attr("src", src); 重新給img元素的scr賦值,不過(guò)這里要注意由于瀏覽器緩存的原因,這里賦值的時(shí)候需要加上一個(gè)動(dòng)態(tài)參數(shù),我這里是使用時(shí)間作為請(qǐng)求參數(shù),因此有了以下的代碼: $(this).attr("src") + "?t=" + nowTime; 這是特別的地方需要注意;好了咋們來(lái)直接測(cè)試登陸是否能從后端判斷驗(yàn)證碼是否正確匹配吧,這里用的是session來(lái)保存獲取驗(yàn)證碼圖片返回的驗(yàn)證代碼,然后在登陸時(shí)候判斷用戶數(shù)據(jù)的驗(yàn)證碼是否和后臺(tái)session的驗(yàn)證一樣:

驗(yàn)證失?。?/p>

.net如何封裝一個(gè)驗(yàn)證碼生成類

驗(yàn)證成功:

.net如何封裝一個(gè)驗(yàn)證碼生成類

好了測(cè)試用例就這么多,如果您覺(jué)得我這個(gè)驗(yàn)證碼生成例子還可以并且您希望使用那么請(qǐng)注意,參數(shù)的傳遞,不同得到的驗(yàn)證碼格式不同,主要方法是:

/// <summary>
 /// 獲取驗(yàn)證碼圖片流
 /// </summary>
 /// <param name="codeLen">驗(yàn)證碼個(gè)數(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);
 }

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI