独上高楼网站
  •    你所在位置:首页 VS.netASP.net控件〉[ASP.NET 控件实作] 图形验证码控件
  • [ASP.NET 控件实作] 图形验证码控件
  • 作者:jeff377  文章来源:博客园  发布日期:2008-10-30  浏览次数:112
  • 打印这篇文章
  • 在网页上常把图形验证码应用在登入或贴文的页面中,因为图形验证码具有机器不易识别的特性,可以防止机器人程序恶意的存取网页。在本文中将实作一个图形验证码的服务器控件,透过简单的属性设定就可以轻易地在网页上套用图形验证码。

    程序代码下载:ASP.NET Server Control - Day28.rar

    一、产生图形验证码

    我们先准备一个产生图形验证码的页面 (ValidateCode.aspx),这个页面主要是绘制验证码图形,并将其写入内存数据流,最后使用 Response.BinaryWrite 将图形输出传递到客户端。当我们输出此验证码图形的同时,会使用 Session("_ValidateCode") 来记录验证码的值,以便后续与使用者输入验证码做比对之用。

    Partial Class ValidateCode
        Inherits System.Web.UI.Page
     
        ''' 
        ''' 產生圖形驗證碼。
        ''' 
        ''' 傳出驗證碼。
        ''' 驗證碼字元數。 
        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
            '顏色列表,用於驗證碼、噪線、噪點
            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}
            '字體列表,用於驗證碼
            Dim oFontNames As String() = {"Times New Roman", "MS Mincho", "Book Antiqua", _
                                          "Gungsuh", "PMingLiU", "Impact"}
            '驗證碼的字元集,去掉了一些容易混淆的字元
            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
     
            '生成驗證碼字串
            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
                    '畫噪線
                    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
                    '畫驗證碼字串
                    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
                    '畫噪點
                    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
     
        ''' 
        ''' 產生圖形驗證碼。
        ''' 
        ''' 記憶體資料流。
        ''' 傳出驗證碼。
        ''' 驗證碼字元數。 
        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
     
            '清除該頁輸出緩存,設置該頁無緩存
            Response.Buffer = True
            Response.ExpiresAbsolute = System.DateTime.Now.AddMilliseconds(0)
            Response.Expires = 0
            Response.CacheControl = "no-cache"
            Response.AppendHeader("Pragma", "No-Cache")
            '將驗證碼圖片寫入記憶體流,並將其以 "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
    我們將此頁面置於 ~/Page/ValidateCode.aspx,當要使用此頁面的圖形驗證碼,只需要在使用 Image 控制項,設定 ImageUrl 為此頁面即可。
    < asp:Image ID="imgValidateCode" runat="server" ImageUrl="~/Page/ValidateCode.aspx" />

     

    二、實作圖形驗證碼控制項

    虽然我们可以使用 Image 控件来呈现 ValidateCode.aspx 页面产生的验证码图形,可是这样只处理一半的动作,因为没有处理「使用者输入的验证码」是否与「图形验证码」相符,所以我们将实作一个图形验证码控件,来处理掉所有相关动作。

    即然上面的示范使用 Image 控件来呈现验证码,所以图形验证码控件就继承 Image 命名为 TBValidateCode。

        < _
        Description("圖形驗證碼控制項"), _
        ToolboxData("<{0}:TBValidateCode runat=server>") _
        > _
        Public Class TBValidateCode
            Inherits System.Web.UI.WebControls.Image
        
        End
    新增 ValidateCodeUrl 属性,设定图形验证码产生页面的网址。 
            ''' 
            ''' 圖形驗證碼產生頁面網址。
            ''' 
            < _
            Description("圖形驗證碼產生頁面網址"), _
            DefaultValue("") _
            > _
            Public Property ValidateCodeUrl() As String
                Get
                    Return FValidateCodeUrl
                End Get
                Set(ByVal value As String)
                    FValidateCodeUrl = value
                End Set
            End Property

     

    覆写 Render 方法,若未设定 ValidateCodeUrl 属性,则预设为 ~/Page/ValidateCode.aspx 这个页面。另外我们在图形的 ondbclick 加上一段客户端指令码,其作用是让用户可以鼠标二下来重新产生一个验证码图形。

            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 = "圖形驗證碼"
                End If
                Me.ToolTip = "滑鼠點二下可重新產生驗證碼"
                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
    另外新增一个 ValidateCode 方法,用来检查输入验证码是否正确。还记得我们在产生验证码图形时,同时把该验证码的值写入 Session("_ValidateCode") 中吧,所以这个方法只是把用户输入的值与 Seesion 中的值做比对。 
            ''' 
            ''' 檢查輸入驗證碼是否正確。
            ''' 
            ''' 輸入驗證碼。
            ''' 驗證成功傳回 True,反之傳回 False。
            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

     

    三、测试程序

    在页面放置一个 TBValidateCode 控件,另外加一个文字框及按钮,供使用者输入验证码后按下「确定」钮后到伺服端做输入值比对的动作。

            < bee:TBValidateCode ID="TBValidateCode1" runat="server" />
            < bee:TBTextBox ID="txtCode" runat="server">bee:TBTextBox>
            < bee:TBButton ID="TBButton1" runat="server" Text="確定" />

     

    在「确定」钮的 Click 事件中,我们使用 TBValidateCode 控件的 ValidateCode 方法判断验证码输入的正确性。

        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("驗證碼輸入正確")
            Else
                Me.Response.Write("驗證碼輸入錯誤!")
            End If
        End Sub

     

    执行程序,页面就会随机产生一个验证码图形。

    image

    输入正确的值按「确定」钮,就会显示「验证码输入正确」的讯息。因为我们在同一页面测试的关系,你会发现 PostBack 后验证码图形又会重新产生,一般正常的做法是验证正确后就导向另一个页面。

    image

    当我们输入错误的值,就会显示「验证码输入错误!」的讯息。

    image

     

  • 打印这篇文章
  • 与本文主题相关的文章
  • 返回首页