[ASP.NET 控件实作 Day28] 图形验证码控件
在網(wǎng)頁(yè)上常把圖形驗(yàn)證碼應(yīng)用在登入或貼文的頁(yè)面中,因?yàn)閳D形驗(yàn)證碼具有機(jī)器不易識(shí)別的特性,可以防止機(jī)器人程序惡意的存取網(wǎng)頁(yè)。在本文中將實(shí)作一個(gè)圖形驗(yàn)證碼的服務(wù)器控件,透過(guò)簡(jiǎn)單的屬性設(shè)定就可以輕易地在網(wǎng)頁(yè)上套用圖形驗(yàn)證碼。
程序代碼下載:ASP.NET Server Control - Day28.rar
?
一、產(chǎn)生圖形驗(yàn)證碼
我們先準(zhǔn)備一個(gè)產(chǎn)生圖形驗(yàn)證碼的頁(yè)面 (ValidateCode.aspx),這個(gè)頁(yè)面主要是繪制驗(yàn)證碼圖形,并將其寫(xiě)入內(nèi)存數(shù)據(jù)流,最后使用 Response.BinaryWrite 將圖形輸出傳遞到客戶端。當(dāng)我們輸出此驗(yàn)證碼圖形的同時(shí),會(huì)使用 Session("_ValidateCode") 來(lái)記錄驗(yàn)證碼的值,以便后續(xù)與使用者輸入驗(yàn)證碼做比對(duì)之用。
Partial Class ValidateCode Inherits System.Web.UI.Page ? ''' <summary> ''' 產(chǎn)生圖形驗(yàn)證碼。 ''' </summary> ''' <param name="Code">傳出驗(yàn)證碼。</param> ''' <param name="CodeLength">驗(yàn)證碼字元數(shù)。</param> Public Function CreateValidateCodeImage(ByRef Code As String, ByVal CodeLength As Integer, _ ByVal Width As Integer, ByVal Height As Integer, ByVal FontSize As Integer) As Bitmap Dim sCode As String = String.Empty '顏色列表,用於驗(yàn)證碼、噪線、噪點(diǎn) Dim oColors As Color() = { _ Drawing.Color.Black, Drawing.Color.Red, Drawing.Color.Blue, Drawing.Color.Green, _ Drawing.Color.Orange, Drawing.Color.Brown, Drawing.Color.Brown, Drawing.Color.DarkBlue} '字體列表,用於驗(yàn)證碼 Dim oFontNames As String() = {"Times New Roman", "MS Mincho", "Book Antiqua", _ "Gungsuh", "PMingLiU", "Impact"} '驗(yàn)證碼的字元集,去掉了一些容易混淆的字元 Dim oCharacter As Char() = {"2"c, "3"c, "4"c, "5"c, "6"c, "8"c, _ "9"c, "A"c, "B"c, "C"c, "D"c, "E"c, _ "F"c, "G"c, "H"c, "J"c, "K"c, "L"c, _ "M"c, "N"c, "P"c, "R"c, "S"c, "T"c, _ "W"c, "X"c, "Y"c} Dim oRnd As New Random() Dim oBmp As Bitmap Dim oGraphics As Graphics Dim N1 As Integer Dim oPoint1 As Drawing.Point Dim oPoint2 As Drawing.Point Dim sFontName As String Dim oFont As Font Dim oColor As Color ? '生成驗(yàn)證碼字串 For N1 = 0 To CodeLength - 1 sCode += oCharacter(oRnd.Next(oCharacter.Length)) Next ? oBmp = New Bitmap(Width, Height) oGraphics = Graphics.FromImage(oBmp) oGraphics.Clear(Drawing.Color.White) Try For N1 = 0 To 4 '畫(huà)噪線 oPoint1.X = oRnd.Next(Width) oPoint1.Y = oRnd.Next(Height) oPoint2.X = oRnd.Next(Width) oPoint2.Y = oRnd.Next(Height) oColor = oColors(oRnd.Next(oColors.Length)) oGraphics.DrawLine(New Pen(oColor), oPoint1, oPoint2) Next ? For N1 = 0 To sCode.Length - 1 '畫(huà)驗(yàn)證碼字串 sFontName = oFontNames(oRnd.Next(oFontNames.Length)) oFont = New Font(sFontName, FontSize, FontStyle.Italic) oColor = oColors(oRnd.Next(oColors.Length)) oGraphics.DrawString(sCode(N1).ToString(), oFont, New SolidBrush(oColor), CSng(N1) * FontSize + 10, CSng(8)) Next ? For i As Integer = 0 To 30 '畫(huà)噪點(diǎn) Dim x As Integer = oRnd.Next(oBmp.Width) Dim y As Integer = oRnd.Next(oBmp.Height) Dim clr As Color = oColors(oRnd.Next(oColors.Length)) oBmp.SetPixel(x, y, clr) Next ? Code = sCode Return oBmp Finally oGraphics.Dispose() End Try End Function ? ''' <summary> ''' 產(chǎn)生圖形驗(yàn)證碼。 ''' </summary> ''' <param name="MemoryStream">記憶體資料流。</param> ''' <param name="Code">傳出驗(yàn)證碼。</param> ''' <param name="CodeLength">驗(yàn)證碼字元數(shù)。</param> Public Sub CreateValidateCodeImage(ByRef MemoryStream As MemoryStream, _ ByRef Code As String, ByVal CodeLength As Integer, _ ByVal Width As Integer, ByVal Height As Integer, ByVal FontSize As Integer) Dim oBmp As Bitmap ? oBmp = CreateValidateCodeImage(Code, CodeLength, Width, Height, FontSize) Try oBmp.Save(MemoryStream, ImageFormat.Png) Finally oBmp.Dispose() End Try End Sub ? Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load Dim sCode As String = String.Empty ? '清除該頁(yè)輸出緩存,設(shè)置該頁(yè)無(wú)緩存 Response.Buffer = True Response.ExpiresAbsolute = System.DateTime.Now.AddMilliseconds(0) Response.Expires = 0 Response.CacheControl = "no-cache" Response.AppendHeader("Pragma", "No-Cache") '將驗(yàn)證碼圖片寫(xiě)入記憶體流,並將其以 "image/Png" 格式輸出 Dim oStream As New MemoryStream() Try CreateValidateCodeImage(oStream, sCode, 4, 100, 40, 18) Me.Session("_ValidateCode") = sCode Response.ClearContent() Response.ContentType = "image/Png" Response.BinaryWrite(oStream.ToArray()) Finally '釋放資源 oStream.Dispose() End Try End Sub End Class?
?
?
?
我們將此頁(yè)面置於 ~/Page/ValidateCode.aspx,當(dāng)要使用此頁(yè)面的圖形驗(yàn)證碼,只需要在使用 Image 控制項(xiàng),設(shè)定 ImageUrl 為此頁(yè)面即可。
<asp:Image ID="imgValidateCode" runat="server" ImageUrl="~/Page/ValidateCode.aspx" />?
?
?
二、實(shí)作圖形驗(yàn)證碼控制項(xiàng)
雖然我們可以使用 Image 控件來(lái)呈現(xiàn) ValidateCode.aspx 頁(yè)面產(chǎn)生的驗(yàn)證碼圖形,可是這樣只處理一半的動(dòng)作,因?yàn)闆](méi)有處理「使用者輸入的驗(yàn)證碼」是否與「圖形驗(yàn)證碼」相符,所以我們將實(shí)作一個(gè)圖形驗(yàn)證碼控件,來(lái)處理掉所有相關(guān)動(dòng)作。
即然上面的示范使用 Image 控件來(lái)呈現(xiàn)驗(yàn)證碼,所以圖形驗(yàn)證碼控件就繼承 Image 命名為 TBValidateCode。
< _ Description("圖形驗(yàn)證碼控制項(xiàng)"), _ ToolboxData("<{0}:TBValidateCode runat=server></{0}:TBValidateCode>") _ > _ Public Class TBValidateCode Inherits System.Web.UI.WebControls.Image End?
?
?
?
新增 ValidateCodeUrl 屬性,設(shè)定圖形驗(yàn)證碼產(chǎn)生頁(yè)面的網(wǎng)址。
''' <summary> ''' 圖形驗(yàn)證碼產(chǎn)生頁(yè)面網(wǎng)址。 ''' </summary> < _ Description("圖形驗(yàn)證碼產(chǎn)生頁(yè)面網(wǎng)址"), _ DefaultValue("") _ > _ Public Property ValidateCodeUrl() As String Get Return FValidateCodeUrl End Get Set(ByVal value As String) FValidateCodeUrl = value End Set End Property?
?
?
覆寫(xiě) Render 方法,若未設(shè)定 ValidateCodeUrl 屬性,則預(yù)設(shè)為 ~/Page/ValidateCode.aspx 這個(gè)頁(yè)面。另外我們?cè)趫D形的 ondbclick 加上一段客戶端指令碼,其作用是讓用戶可以鼠標(biāo)二下來(lái)重新產(chǎn)生一個(gè)驗(yàn)證碼圖形。
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter) Dim sUrl As String Dim sScript As String ? sUrl = Me.ValidateCodeUrl If String.IsNullOrEmpty(sUrl) Then sUrl = "~/Page/ValidateCode.aspx" End If If Me.BorderWidth = Unit.Empty Then Me.BorderWidth = Unit.Pixel(1) End If If Me.AlternateText = String.Empty Then Me.AlternateText = "圖形驗(yàn)證碼" End If Me.ToolTip = "滑鼠點(diǎn)二下可重新產(chǎn)生驗(yàn)證碼" Me.ImageUrl = sUrl If Not Me.DesignMode Then sScript = String.Format("this.src='{0}?flag='+Math.random();", Me.Page.ResolveClientUrl(sUrl)) Me.Attributes("ondblclick") = sScript End If Me.Style(HtmlTextWriterStyle.Cursor) = "pointer" ? MyBase.Render(writer) End Sub?
?
?
另外新增一個(gè) ValidateCode 方法,用來(lái)檢查輸入驗(yàn)證碼是否正確。還記得我們?cè)诋a(chǎn)生驗(yàn)證碼圖形時(shí),同時(shí)把該驗(yàn)證碼的值寫(xiě)入 Session("_ValidateCode") 中吧,所以這個(gè)方法只是把用戶輸入的值與 Seesion 中的值做比對(duì)。
''' <summary> ''' 檢查輸入驗(yàn)證碼是否正確。 ''' </summary> ''' <param name="Code">輸入驗(yàn)證碼。</param> ''' <returns>驗(yàn)證成功傳回 True,反之傳回 False。</returns> Public Function ValidateCode(ByVal Code As String) As Boolean If Me.Page.Session(SessionKey) Is Nothing Then Return False If SameText(CCStr(Me.Page.Session(SessionKey)), Code) Then Return True Else Return False End If End Function?
?
?
?
三、測(cè)試程序
在頁(yè)面放置一個(gè) TBValidateCode 控件,另外加一個(gè)文字框及按鈕,供使用者輸入驗(yàn)證碼后按下「確定」鈕后到伺服端做輸入值比對(duì)的動(dòng)作。
<bee:TBValidateCode ID="TBValidateCode1" runat="server" /> <bee:TBTextBox ID="txtCode" runat="server"></bee:TBTextBox> <bee:TBButton ID="TBButton1" runat="server" Text="確定" />?
?
?
?
在「確定」鈕的 Click 事件中,我們使用 TBValidateCode 控件的 ValidateCode 方法判斷驗(yàn)證碼輸入的正確性。
Protected Sub TBButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles TBButton1.Click If TBValidateCode1.ValidateCode(txtCode.Text) Then Me.Response.Write("驗(yàn)證碼輸入正確") Else Me.Response.Write("驗(yàn)證碼輸入錯(cuò)誤!") End If End Sub?
?
?
執(zhí)行程序,頁(yè)面就會(huì)隨機(jī)產(chǎn)生一個(gè)驗(yàn)證碼圖形。
輸入正確的值按「確定」鈕,就會(huì)顯示「驗(yàn)證碼輸入正確」的訊息。因?yàn)槲覀冊(cè)谕豁?yè)面測(cè)試的關(guān)系,你會(huì)發(fā)現(xiàn) PostBack 后驗(yàn)證碼圖形又會(huì)重新產(chǎn)生,一般正常的做法是驗(yàn)證正確后就導(dǎo)向另一個(gè)頁(yè)面。
當(dāng)我們輸入錯(cuò)誤的值,就會(huì)顯示「驗(yàn)證碼輸入錯(cuò)誤!」的訊息。
?
備注:本文同步發(fā)布于「第一屆iT邦幫忙鐵人賽」,如果你覺(jué)得這篇文章對(duì)您有幫助,記得連上去推鑒此文增加人氣 ^^
http://ithelp.ithome.com.tw/question/10013361
http://ithelp.ithome.com.tw/question/10013365
轉(zhuǎn)載于:https://www.cnblogs.com/jeff377/archive/2008/10/29/1322471.html
總結(jié)
以上是生活随笔為你收集整理的[ASP.NET 控件实作 Day28] 图形验证码控件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。