[ASP.NET]幫Login加上驗證碼

驗證碼一直是避免網頁機器人透過程式的方式自動登入、輸入的一種常見方式,本篇參考Dotjum的【Captcha 安全碼[ASP.NET] 產生驗證圖片字】,修改成VB.NET的版本而成。並且配合Login登入驗證控制項來處理,有需要的請參考看看。

緣起:

驗證碼一直是避免網頁機器人透過程式的方式自動登入、輸入的一種常見方式,本篇參考Dotjum的【Captcha 安全碼[ASP.NET] 產生驗證圖片字】,修改成VB.NET的版本而成。並且配合Login登入驗證控制項來處理,有需要的請參考看看。

準備產生驗證碼程式:

  1. 首先,我們先新增一個產生驗證圖形、並且將驗證的碼存到Session等候驗證。先新增一個ASP.NET檔案,檔名就稱為【CheckImageCode.aspx】
  2. 在aspx裡面不用做任何的安排,直接編寫後置程式碼【CheckImageCode.aspx.vb】
  3. 新增一個亂數產生驗證碼的Private Function,並且將亂數產生的驗證碼存放在Session裡面,相關程式碼如下:
    其中產生驗證碼,透過取得0與A的Ascii Code再加上亂數取得的數字分別數字mod 10、文字mod 26,產生亂碼
    Private Function GenerateCheckCode() As String
        Dim number As Integer
        Dim code As Char
        Dim checkCode As String = String.Empty
        Dim random As System.Random = New Random()
        '要製造出幾個驗證碼
        For i As Integer = 0 To 3
            'number = random.[Next]()
            number = random.Next
            '亂數決定哪一個是數字或字母
            If number Mod 2 = 0 Then
                code = CChar(ChrW(Asc("0") + (number Mod 10)))
            Else
                code = CChar(ChrW(Asc("A") + (number Mod 26)))
            End If
            checkCode += code.ToString()
        Next
        '寫入Session
        Session("CheckCode") = checkCode
        Return checkCode
    End Function
  4. 新增一個畫出驗證碼圖形的Private Sub,而由於需要產生圖形,先Import 【System.Drawing】,接著撰寫畫出驗證碼的Function,並且亂數產生雜點,避免網路機器人透過圖形辨識來識別出驗證碼
    Private Sub CreateCheckCodeImage(ByVal checkCode As String)
        If checkCode Is Nothing OrElse checkCode.Trim() = [String].Empty Then
            Return
        End If
    
        'System.Drawing.Bitmap image = new System.Drawing.Bitmap((int)Math.Ceiling((checkCode.Length * 12.5)), 22);
        'System.Drawing.Bitmap image = new System.Drawing.Bitmap((int)Math.Ceiling((checkCode.Length * 20)), 40);
        Dim image As New System.Drawing.Bitmap(100, 30)
    
        Dim g As Graphics = Graphics.FromImage(image)
    
        Try
            '生成隨機生成器
            Dim random As New Random()
    
            '清空圖片背景色
            g.Clear(Color.White)
    
            '畫圖片的背景噪音線
            For i As Integer = 0 To 24
                Dim x1 As Integer = random.[Next](image.Width)
                Dim x2 As Integer = random.[Next](image.Width)
                Dim y1 As Integer = random.[Next](image.Height)
                Dim y2 As Integer = random.[Next](image.Height)
    
                g.DrawLine(New Pen(Color.Silver), x1, y1, x2, y2)
            Next
    
            Dim font As Font = New System.Drawing.Font("Arial", 22, (System.Drawing.FontStyle.Bold Or System.Drawing.FontStyle.Italic))
            Dim brush As New System.Drawing.Drawing2D.LinearGradientBrush(New Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2F, True)
            'g.DrawString(checkCode, font, brush, 2, 2);
            g.DrawString(checkCode, font, brush, 2, 2)
    
            '畫圖片的前景噪音點
            For i As Integer = 0 To 499
                Dim x As Integer = random.[Next](image.Width)
                Dim y As Integer = random.[Next](image.Height)
    
                image.SetPixel(x, y, Color.FromArgb(random.Next))
            Next
    
            '畫圖片的邊框線
            g.DrawRectangle(New Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1)
    
            Dim ms As New System.IO.MemoryStream()
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif)
            Response.ClearContent()
            Response.ContentType = "image/Gif"
            Response.BinaryWrite(ms.ToArray())
        Finally
            g.Dispose()
            image.Dispose()
        End Try
    End Sub
  5. 最後,在【Page Load】事件中呼叫此兩個Function,產生驗證碼、Cookie、圖形。
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        CreateCheckCodeImage(GenerateCheckCode())
    End Sub

安排Login相關事宜

這個部分,要麻煩讀者您參考小喵的這篇【ASP.NET的驗證與授權機制(動態錄影說明)】,準備好登入的相關設定。

準備Login的資料夾與畫面

小喵新增一個目錄【Account】,把登入(Login.aspx)、產生驗證碼(CheckImageCode.aspx)的aspx放在此目錄,還需要設定此目錄【允許所有使用者瀏覽】,這很重要,如果此目錄的設定是【拒絕匿名使用者】,那麼【產生驗證碼】的aspx將因為無權限而無法產生。可以在Account這資料夾裡面,設定Web.Config如下,就可以讓此資料夾允許任何使用者。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <authorization>
            <allow users="?" />
        </authorization>
    </system.web>
</configuration>

接著來安排Login.aspx的內容,首先準備畫面如下:

<asp:Image ID="imgChkCode" ImageUrl="~/Account/CheckImageCode.aspx" runat="server" />
<asp:Button ID="btnReGenCode" runat="server" Text="重產驗證碼" />
<br />
<asp:TextBox ID="txtChkCode" runat="server"></asp:TextBox>
<asp:Login ID="Login1" runat="server">
</asp:Login>
<asp:Label ID="lblMsg" runat="server" Text=""></asp:Label>

我們放置一個Image控制項,而source指向產生驗證碼的CheckImageCode.aspx,這樣就能夠產生驗證碼,並且存好Session等待驗證,而準備lblMsg來顯示驗證的訊息。驗證的相關程式碼如下:

Protected Sub Login1_Authenticate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.AuthenticateEventArgs) Handles Login1.Authenticate
	If String.Compare(Me.txtChkCode.Text.ToUpper, Session("CheckCode")) <> 0 Then
		Me.lblMsg.Text = "驗證碼錯誤!!"
	Else
		If Membership.ValidateUser(Me.Login1.UserName, Me.Login1.Password) Then
			FormsAuthentication.RedirectFromLoginPage(Me.Login1.UserName, Me.Login1.RememberMeSet)
		End If
	End If
    '2018/5/10 增加:由於驗證圖形是透過圖形讀取時產生,如果不透過頁面重新讀取,驗證碼就不會變換,變成驗證碼是固定,這樣會讓機器人有可乘之機
    '因此,無論驗證是否成功,立刻亂數修改驗證碼,讓原有的驗證碼失效
    Session("CheckCode") = RdnGenCode()
End Sub

LoginChkCode

 


以下是簽名:


Microsoft MVP
Visual Studio and Development Technologies
(2005~2019/6) 
topcat
Blog:http://www.dotblogs.com.tw/topcat