MVC採用HtmlHelper擴展和Filter封裝驗證碼的功能

来源:http://www.cnblogs.com/chenlinzhi/archive/2016/03/14/5277436.html
-Advertisement-
Play Games

最近因為有個項目除了登錄還有其他很多地方需要用到驗證碼的功能,所以想到了採用HtmlHelper和ActionFilter封裝一個驗證碼的功能,以便能夠重覆調用。封裝好以後調用很方便,只需在View中調用Html擴展好的方法,相應的Action加上驗證功能的Filter就行了。 首先寫一個能夠隨機生


最近因為有個項目除了登錄還有其他很多地方需要用到驗證碼的功能,所以想到了採用HtmlHelper和ActionFilter封裝一個驗證碼的功能,以便能夠重覆調用。封裝好以後調用很方便,只需在View中調用Html擴展好的方法,相應的Action加上驗證功能的Filter就行了。

首先寫一個能夠隨機生成數字的圖片的類,園子里有一大把這樣的文章,直接拿過來就用了,自己懶得寫了。

  1   public class CaptchaRender
  2     {
  3         public CaptchaRender()
  4         {
  5         }
  6 
  7         /// <summary>
  8         /// 驗證碼的最大長度
  9         /// </summary>
 10         public int MaxLength
 11         {
 12             get { return 10; }
 13         }
 14 
 15         /// <summary>
 16         /// 驗證碼的最小長度
 17         /// </summary>
 18         public int MinLength
 19         {
 20             get { return 1; }
 21         }
 22 
 23         /// <summary>
 24         /// 生成驗證碼
 25         /// </summary>
 26         /// <param name="length">指定驗證碼的長度</param>
 27         /// <returns></returns>
 28         public string CreateValidateCode(int length)
 29         {
 30             int[] randMembers = new int[length];
 31             int[] validateNums = new int[length];
 32             string validateNumberStr = "";
 33             //生成起始序列值
 34             int seekSeek = unchecked((int) DateTime.Now.Ticks);
 35             Random seekRand = new Random(seekSeek);
 36             int beginSeek = (int) seekRand.Next(0, Int32.MaxValue - length*10000);
 37             int[] seeks = new int[length];
 38             for (int i = 0; i < length; i++)
 39             {
 40                 beginSeek += 10000;
 41                 seeks[i] = beginSeek;
 42             }
 43             //生成隨機數字
 44             for (int i = 0; i < length; i++)
 45             {
 46                 Random rand = new Random(seeks[i]);
 47                 int pownum = 1*(int) Math.Pow(10, length);
 48                 randMembers[i] = rand.Next(pownum, Int32.MaxValue);
 49             }
 50             //抽取隨機數字
 51             for (int i = 0; i < length; i++)
 52             {
 53                 string numStr = randMembers[i].ToString();
 54                 int numLength = numStr.Length;
 55                 Random rand = new Random();
 56                 int numPosition = rand.Next(0, numLength - 1);
 57                 validateNums[i] = Int32.Parse(numStr.Substring(numPosition, 1));
 58             }
 59             //生成驗證碼
 60             for (int i = 0; i < length; i++)
 61             {
 62                 validateNumberStr += validateNums[i].ToString();
 63             }
 64             return validateNumberStr;
 65         }
 66 
 67         /// <summary>
 68         /// 創建驗證碼的圖片
 69         /// </summary>
 70         /// <param name="containsPage">要輸出到的page對象</param>
 71         /// <param name="validateNum">驗證碼</param>
 72         public byte[] CreateValidateGraphic(string validateCode)
 73         {
 74             Bitmap image = new Bitmap((int) Math.Ceiling(validateCode.Length*12.0), 22);
 75             Graphics g = Graphics.FromImage(image);
 76             try
 77             {
 78                 //生成隨機生成器
 79                 Random random = new Random();
 80                 //清空圖片背景色
 81                 g.Clear(Color.White);
 82                 //畫圖片的干擾線
 83                 for (int i = 0; i < 25; i++)
 84                 {
 85                     int x1 = random.Next(image.Width);
 86                     int x2 = random.Next(image.Width);
 87                     int y1 = random.Next(image.Height);
 88                     int y2 = random.Next(image.Height);
 89                     g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2);
 90                 }
 91                 Font font = new Font("Arial", 12, (FontStyle.Bold | FontStyle.Italic));
 92                 LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height),
 93                     Color.Blue, Color.DarkRed, 1.2f, true);
 94                 g.DrawString(validateCode, font, brush, 3, 2);
 95                 //畫圖片的前景干擾點
 96                 for (int i = 0; i < 100; i++)
 97                 {
 98                     int x = random.Next(image.Width);
 99                     int y = random.Next(image.Height);
100                     image.SetPixel(x, y, Color.FromArgb(random.Next()));
101                 }
102                 //畫圖片的邊框線
103                 g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1);
104                 //保存圖片數據
105                 MemoryStream stream = new MemoryStream();
106                 image.Save(stream, ImageFormat.Jpeg);
107                 //輸出圖片流
108                 return stream.ToArray();
109             }
110             finally
111             {
112                 g.Dispose();
113                 image.Dispose();
114             }
115         }
116 
117         /// <summary>
118         /// 得到驗證碼圖片的長度
119         /// </summary>
120         /// <param name="validateNumLength">驗證碼的長度</param>
121         /// <returns></returns>
122         public static int GetImageWidth(int validateNumLength)
123         {
124             return (int) (validateNumLength*12.0);
125         }
126 
127         /// <summary>
128         /// 得到驗證碼的高度
129         /// </summary>
130         /// <returns></returns>
131         public static double GetImageHeight()
132         {
133             return 22.5;
134         }
135     }
View Code

然後寫HtmlHelper類型的擴展方法,以便在View中調用。

 1  public static class HtmlExtensions
 2     {
 3         /// <summary>
 4         /// 生成驗證碼
 5         /// </summary>
 6         /// <param name="helper">當前View的HtmlHelper</param>
 7         /// <param name="urlHelper">當前View的UrlHelper</param>
 8         /// <returns>帶驗證碼的Img</returns>
 9         public static MvcHtmlString GenerateCaptcha(this HtmlHelper helper, UrlHelper urlHelper)
10         {
11             var sb = new StringBuilder();
12             var builder = new TagBuilder("img");
13             builder.Attributes.Add("id", "captcha");
14             builder.Attributes.Add("style", "cursor:pointer");
15             builder.Attributes.Add("src", urlHelper.Action("GetCaptcha", "Common"));
16             builder.Attributes.Add("alt", "單擊刷新驗證碼");
17             sb.AppendLine(builder.ToString(TagRenderMode.Normal));
18 
19             sb.AppendLine("<script>");
20             sb.AppendLine("$(function(){");
21             sb.AppendLine("$('#captcha').bind('click',function(){this.src='" +
22                           urlHelper.Action("GetCaptcha", "Common") + "?time='+(new Date()).getTime()})");
23             sb.AppendLine("})");
24             sb.AppendLine("</script>");
25 
26             return MvcHtmlString.Create(sb.ToString());
27         }
28 
29         /// <summary>
30         /// 生成驗證碼
31         /// </summary>
32         /// <typeparam name="TModel">Model</typeparam>
33         /// <typeparam name="TValue">Model的值</typeparam>
34         /// <param name="helper">當前View的HtmlHelper</param>
35         /// <param name="expression">Model屬性的Lambda表達式</param>
36         /// <param name="urlHelper">當前View的UrlHelper</param>
37         /// <returns>封裝好的label,textbox,帶驗證碼的img</returns>
38         public static MvcHtmlString GenerateCaptcha<TModel, TValue>(this HtmlHelper<TModel> helper,
39             Expression<Func<TModel, TValue>> expression, UrlHelper urlHelper)
40         {
41             StringBuilder sb = new StringBuilder();
42             var label = helper.LabelFor(expression, new {}, "");
43             var textbox = helper.TextBoxFor(expression);
44             var captcha = GenerateCaptcha(helper, urlHelper);
45             sb.AppendLine(label.ToHtmlString());
46             sb.AppendLine(textbox.ToHtmlString());
47             sb.AppendLine(captcha.ToHtmlString());
48 
49             return MvcHtmlString.Create(sb.ToString());
50         }
51     }
View Code

其中builder.Attributes.Add("src", urlHelper.Action("GetCaptcha", "Common"))調用了用於生成帶驗證碼的GetCaptcha方法,該方法後面會提到,本人寫在
CommonController當中,GetCaptcha方法其實就是調用了上面的CaptchaRender類中的CreateValidateCode方法,生成驗證碼輸出到View。

GenerateCaptcha<TModel, TValue>這個泛型方法可以綁定視圖模型中驗證碼的欄位,並且生成label,textbox,image標簽,還有相關的腳本,在View中輸出的內容如下:

<label for="Captcha">驗證碼:</label>
<input id="Captcha" name="Captcha" type="text" value="" />
<img alt="單擊刷新驗證碼" id="captcha" src="/Common/GetCaptcha" style="cursor:pointer"></img>
<script>
$(function(){
$('#captcha').bind('click',function(){this.src='/Common/GetCaptcha?time='+(new Date()).getTime()})
})
</script>

CommonController中的GetCaptcha方法如下:

        /// <summary>
        /// 生成驗證碼
        /// </summary>
        /// <returns></returns>
        public ActionResult GetCaptcha()
        {
            CaptchaRender captcha = new CaptchaRender();
            string code = captcha.CreateValidateCode(5);
            TempData["Captcha"] = code;
            byte[] bytes = captcha.CreateValidateGraphic(code);
            return File(bytes, "image/jpeg");
        }

TempData["Captcha"] = code是把生成的驗證碼放到TempData中,以便在ActionFilter中獲取到驗證碼的值,ActionFilter方法如下:

 1     public class CaptchaValidatorAttribute : ActionFilterAttribute
 2     {
 3         private const string CaptchaFormValue = "Captcha";
 4         public override void OnActionExecuting(ActionExecutingContext filterContext)
 5         {
 6             bool valid = false;
 7 
 8             foreach (var value in filterContext.HttpContext.Request.Form.AllKeys)
 9             {
10                 if (value.Contains(CaptchaFormValue))
11                 {
12                     valid = (string) filterContext.Controller.TempData["Captcha"] ==
13                             filterContext.HttpContext.Request.Form[value];
14                     break;
15                 }
16             }
17             filterContext.ActionParameters["captchaValid"] = valid;
18             base.OnActionExecuting(filterContext);
19         }
20     }
View Code

CaptchaValidator過濾器其實就是在相應的Action執行前,遍歷Form窗體變數集合的所有Key值,把保存在TempData["Captcha"]中的驗證碼的值和Form窗體中name="Captcha"(Key值="Captcha")的Textbox的值(用戶輸入的驗證碼)比較,然後再把比較後的bool值賦值給用CaptchaValidator特性修飾的Action的captchaValid參數。(Action根據captchaValid參數的值去判斷是否通過驗證)。

View視圖代碼調用如下:

@Html.GenerateCaptcha(m => m.Captcha, Url)

Action調用如下:

一定要記得Action的參數名稱captchaValid和過濾器中 filterContext.ActionParameters["captchaValid"]一致。

效果圖如下:

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  •  
  •  
  • 最後要用一方法判斷ip地址是否正確,直接用.Net現成的類,方法如下:
  • 某一時候,為文本框(TextBox)裝飾個水印。它有兩種狀態,一是blur和focus。因此,我們可以在Javascript寫兩個事件: 演示:    
  • 【問】 在C#和Visual Basic的轉換中,以下一些轉換的用法和區別是什麼呢? [C#] [VB.NET] 【錯誤回答】 沒有區別,因為運行了之後都可以正常轉化。 【正解】 光從運行結果來看當然是毫無區別,因為題目所給出的僅僅是一部分的例子,不是全部。許多初學者容易產生“以偏概全”的錯誤認識。
  • 我希望能理解在瀏覽器輸入URL並敲擊回車來請求一個ASP.NET MVC網站的頁面之後發生的任何事情。 為什麼需要關心這些?有兩個原因。首先是因為ASP.NET MVC是一個擴展性非常強的框架。例如,我們可以插入不同的ViewEngine來控制網站內容呈現的方式。我們還可以定義控制器生成和分配到某個
  • 事件,定義了事件成員的類型允許類型或類型的實例通知其它對象發生了特定的事情。 按照我自己的理解而言,事件可以被(方法)關註,也可以被(方法)取消關註,事件發生後關註了事件的一方會瞭解到,並對事件做出相應的應對(執行方法)。(我每次都是這麼理解的,這樣從字面意義上更好理解一點) 眾所周知,事件實際上就
  • 什麼是Asp.Net頁面生命周期 當我們在瀏覽器地址欄中輸入網址,回車查看頁面時,這時會向伺服器端(IIS)發送一個request請求,伺服器就會判斷發送過來的請求頁面,  完全識別 HTTP 頁面處理程式類後,ASP.NET 運行時將調用處理程式的 ProcessRequest 方法來處理請求,來
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...