實作ASP.NET MVC CAPTCHA驗證碼機制

CAPTCHA

依wiki的說明:「全自動區分電腦和人類的圖靈測試(英語:Completely Automated Public Turing test to tell Computers and Humans Apart,簡稱CAPTCHA),俗稱驗證碼。

產生驗證碼

首先我們必須先撰寫一支產生驗證碼圖片的程式,程式碼主要是是透過Bitmap物件來幫我們產生圖檔(想成一張空白畫布),然後在畫布上畫上我們要的內容(可以是任意內容)。

01public void VerificationCode()
02{
03    // 是否產生驗證碼
04    bool isCreate = true;
05 
06    // Session["CreateTime"]: 建立驗證碼的時間
07    if (Session["CreateTime"] == null)
08    {
09        Session["CreateTime"] = DateTime.Now;
10    }
11    else
12    {
13        DateTime startTime = Convert.ToDateTime(Session["CreateTime"]);
14        DateTime endTime = Convert.ToDateTime(DateTime.Now);
15        TimeSpan ts = endTime - startTime;
16 
17 
18        // 重新產生驗證碼的間隔
19        if (ts.Minutes > 15)
20        {
21            isCreate = true;
22            Session["CreateTime"] = DateTime.Now;
23        }
24        else
25        {
26            isCreate = false;
27        }
28    }
29 
30    Response.ContentType = "image/gif";
31    //建立 Bitmap 物件和繪製
32    Bitmap basemap = new Bitmap(200, 60);
33    Graphics graph = Graphics.FromImage(basemap);
34    graph.FillRectangle(new SolidBrush(Color.White), 0, 0, 200, 60);
35    Font font = new Font(FontFamily.GenericSerif, 48, FontStyle.Bold, GraphicsUnit.Pixel);
36    Random random = new Random();
37    // 英數
38    //string letters = "ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijklmnpqrstuvwxyz0123456789";
39    // 天干地支生肖
40    string letters = "甲乙丙丁戊己庚辛壬癸子丑寅卯辰巳午未申酉戍亥鼠牛虎免龍蛇馬羊猴雞狗豬";
41    string letter;
42    StringBuilder sb = new StringBuilder();
43 
44 
45    if (isCreate)
46    {
47        // 加入隨機二個字
48        // 英文4 ~ 5字,中文2 ~ 3字
49        for (int word = 0; word < 2; word++)
50        {
51            letter = letters.Substring(random.Next(0, letters.Length - 1), 1);
52            sb.Append(letter);
53 
54 
55            // 繪製字串
56            graph.DrawString(letter, font, new SolidBrush(Color.Black), word * 38, random.Next(0, 15));
57        }
58    }
59    else
60    {
61        // 使用先前的驗證碼來產生
62        string currentCode = Session["ValidateCode"].ToString();
63        sb.Append(currentCode);
64 
65        foreach (char item in currentCode)
66        {
67            letter = item.ToString();
68            // 繪製字串
69            graph.DrawString(letter, font, new SolidBrush(Color.Black), currentCode.IndexOf(item) * 38, random.Next(0, 15));
70        }
71    }
72 
73 
74    // 混亂背景
75    Pen linePen = new Pen(new SolidBrush(Color.Black), 2);
76    for (int x = 0; x < 10; x++)
77    {
78        graph.DrawLine(linePen, new Point(random.Next(0, 199), random.Next(0, 59)), new Point(random.Next(0, 199), random.Next(0, 59)));
79    }
80 
81    // 儲存圖片並輸出至stream     
82    basemap.Save(Response.OutputStream, ImageFormat.Gif);
83    // 將產生字串儲存至 Sesssion
84    Session["ValidateCode"] = sb.ToString();
85    Response.End();
86}

內容想呈現中文或英文選擇letters變數的內容即可。

表單使用CAPTCHA

要在MVC的View Page去取得我們的CAPTCHA驗證碼圖也很簡單,只需要在<img src="圖片路徑">即可。

Controller

1public ActionResult Index()
2{
3    Session["User"] = "Bruce";
4 
5    return View();
6}

在Index裡為何要寫那行Session呢?

01<h2>Captcha測試</h2>
02 
03@using (Html.BeginForm("ValidateCode", "Captcha"))
04{
05    <fieldset>
06    <legend>驗證碼</legend>
07        <img src="@Url.Action("VerificationCode")" alt="驗證碼" />
08        @Html.TextBox("InputCode", null, new { placeholder="請輸入驗證碼" })
09        <input type="submit" value="確定" />
10    </fieldset>
11}
12 
13<hr />
14 
15<h2>Captcha測試(AJAX)</h2>
16 
17<div>
18    驗證結果:<span id="status"></span>
19</div>
20 
21@using (Ajax.BeginForm("ValidateCode", "Captcha", new AjaxOptions() { UpdateTargetId = "status" }))
22{
23    <fieldset>
24        <legend>驗證碼</legend>
25        <img src="@Url.Action("VerificationCode")" alt="驗證碼" />
26        @Html.TextBox("InputCode", null, new { placeholder = "請輸入驗證碼" })
27        <input type="submit" value="確定" />
28    </fieldset>
29}
30 
31@section scripts
32{
33    <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
34}

驗證碼的檢查也很合適使用AJAX來進行確認,各位可以測試一般表單和AJAX效果的表單。

驗證輸入

01public ActionResult ValidateCode(string InputCode)
02{
03 if (InputCode == null)
04     return Content("輸入空白");
05 
06    if (InputCode.Trim().ToLower().Equals(Session["ValidateCode"].ToString().ToLower()))
07    {
08        return Content("成功");
09    }
10    else
11    {
12        return Content("失敗");
13    }
14}

如果是選擇使用中文內容,可不需要加上.ToLower()方法。

以上只是個簡單範例研究,中英混合也許是個不錯的方法,但要考慮好你的用戶群是否有看不懂中文。

另外,自己造輪子…還是不要的好,NuGet有滿滿的Captcha套件可以使用。

參考程式碼:Image Verification Code for Logging

3 則留言:

  1. 請問,我在驗證輸入時,Session["ValidateCode"] is null,需要跑第二次才會有值,一直不知道為什麼@@

    回覆刪除
  2. 您好,我是用 MVC5+ ASP.NET+C#,我用了程式碼後,發現驗證結果那一塊會有問題,無法顯示。
    另外有沒有辦法結合 Ajax Reload 圖形???

    回覆刪除
  3. 您好,我是用 MVC5+ASP.NET+AJAX,使用程式碼後,發現 Ajax的測試結果會有問題,會無法顯示。
    另外,有辦法結合 Ajax Reload 圖形嗎?
    我寫了很多次都失敗ˊˋ

    回覆刪除

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。