在網頁上常把圖形驗證碼應用在登入或貼文的頁面中,因為圖形驗證碼具有機器不易識別的特性,可以防止機器人程式惡意的存取網頁。在本文中將實作一個圖形驗證碼的伺服器控制項,透過簡單的屬性設定就可以輕易地在網頁上套用圖形驗證碼。
在網頁上常把圖形驗證碼應用在登入或貼文的頁面中,因為圖形驗證碼具有機器不易識別的特性,可以防止機器人程式惡意的存取網頁。在本文中將實作一個圖形驗證碼的伺服器控制項,透過簡單的屬性設定就可以輕易地在網頁上套用圖形驗證碼。
程式碼下載:ASP.NET Server Control - Day28.rar
一、產生圖形驗證碼
我們先準備一個產生圖形驗證碼的頁面 (ValidateCode.aspx),這個頁面主要是繪製驗證碼圖形,並將其寫入記憶體資料流,最後使用 Response.BinaryWrite 將圖形輸出傳遞到用戶端。當我們輸出此驗證碼圖形的同時,會使用 Session("_ValidateCode") 來記錄驗證碼的值,以便後續與使用者輸入驗證碼做比對之用。
Partial Class ValidateCode
Inherits System.Web.UI.Page
''' <summary>
''' 產生圖形驗證碼。
''' </summary>
''' <param name="Code">傳出驗證碼。</param>
''' <param name="CodeLength">驗證碼字元數。</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
'顏色列表,用於驗證碼、噪線、噪點
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
''' <summary>
''' 產生圖形驗證碼。
''' </summary>
''' <param name="MemoryStream">記憶體資料流。</param>
''' <param name="Code">傳出驗證碼。</param>
''' <param name="CodeLength">驗證碼字元數。</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
'清除該頁輸出緩存,設置該頁無緩存
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></{0}:TBValidateCode>") _
> _
Public Class TBValidateCode
Inherits System.Web.UI.WebControls.Image
End
新增 ValidateCodeUrl 屬性,設定圖形驗證碼產生頁面的網址。
''' <summary>
''' 圖形驗證碼產生頁面網址。
''' </summary>
< _
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 中的值做比對。
''' <summary>
''' 檢查輸入驗證碼是否正確。
''' </summary>
''' <param name="Code">輸入驗證碼。</param>
''' <returns>驗證成功傳回 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
三、測試程式
在頁面放置一個 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
執行程式,頁面就會隨機產生一個驗證碼圖形。
輸入正確的值按「確定」鈕,就會顯示「驗證碼輸入正確」的訊息。因為我們在同一頁面測試的關係,你會發現 PostBack 後驗證碼圖形又會重新產生,一般正常的做法是驗證正確後就導向另一個頁面。
當我們輸入錯誤的值,就會顯示「驗證碼輸入錯誤!」的訊息。
備註:本文同步發佈於「第一屆iT邦幫忙鐵人賽」,如果你覺得這篇文章對您有幫助,記得連上去推鑒此文增加人氣 ^^
http://ithelp.ithome.com.tw/question/10013361
http://ithelp.ithome.com.tw/question/10013365