ASP.NET Membership CAPTCHA VB.NET Code Example

The ASP.NET Membership Captcha example project shows how to integrate BotDetect CAPTCHA validation with standard ASP.NET Membership functionality used in ASP.NET Login and CreateUserWizard controls.

First Time Here?

Check the BotDetect ASP.NET WebForms Captcha Quickstart for key integration steps.

To prevent bots from trying to guess the login info by brute force submission of a large number of common values, the visitor first has to prove they are human (by solving the Captcha), and only then is their username and password submission checked against the authentication data store.

Also, if they enter an invalid username + password combination three times, they have to solve the Captcha again. This prevents attempts in which the attacker would first solve the Captcha themselves, and then let a bot brute-force the authentication info.

To keep the example code simple, the example doesn't access a data store to authenticate the user, but accepts all logins with usernames and passwords at least 5 characters long as valid.

And to prevent bots from registering user accounts, the Register page Captcha has to be solved before user details are recorded.

Download the BotDetect ASP.NET CAPTCHA Generator archive to run this example
  • C#
  • VB.NET

Visual Studio 2017, 2015, 2013 / .NET 4.5.1 and onwards

Since ASP.NET Membership has been deprecated in Visual Studio 2013 and replaced with ASP.NET Identity, there is no Visual Studio 2013 version of the ASP.NET Membership Captcha code example. You can see how to integrate BotDetect Captcha validation into ASP.NET WebForms applications using ASP.NET Identity user management in the ASP.NET WebForms Application Template Captcha code example.

Visual Studio 2012, 2010, 2008, 2005 / .NET 4.5, .NET 4.0, .NET 3.5, .NET 2.0

Within this page, the root folder of the extracted archive is referred as the <BDC-DIR>.

This example is in the <BDC-DIR>/lgcy-on-lgcy/examples/t_api-captcha-webforms-web.security.membership/vbnet/ folder; and contains the following files:

Default.aspx

<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Default.aspx.vb" 
Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>BotDetect CAPTCHA ASP.NET Membership Example</title>
  <link type="text/css" rel="Stylesheet" href="StyleSheet.css" />
</head>
<body>
  <form id="form1" runat="server">
    <h1>BotDetect CAPTCHA ASP.NET Membership Example</h1>
    <fieldset>
      <legend>Page protected with ASP.NET authentication</legend>
      <p>This page can only be seen after successful Captcha validation and 
      username/password authentication.</p>
      <asp:LinkButton Text="Sign out" runat="server" ID="SignOutButton" 
      OnClick="SignOutButton_Click"></asp:LinkButton>
    </fieldset>
  </form>
</body>
</html>

This page has no special code, but is meant to only be seen by authenticated users. It will be displayed to users who pass both the Captcha validation and the username / password authentication.

Default.aspx.vb

Partial Class _Default
  Inherits System.Web.UI.Page

  Protected Sub SignOutButton_Click(ByVal sender As Object, 
  ByVal e As System.EventArgs) Handles SignOutButton.Click
    FormsAuthentication.SignOut()
    Response.Redirect("Default.aspx?ref=signout", True)
  End Sub
End Class

Login.aspx

<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Login.aspx.vb" 
Inherits="Login" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>Login</title>
  <link type="text/css" rel="Stylesheet" href="StyleSheet.css" />
</head>
<body>
  <form id="form1" runat="server">
    <h1>BotDetect CAPTCHA ASP.NET Membership Example</h1>
    <fieldset>
      <legend>CAPTCHA Validation in a <code>Login</code> control</legend>
      <asp:Login ID="ExampleLogin" runat="server" 
      OnAuthenticate="ExampleLogin_Authenticate">
        <LayoutTemplate>
          <table border="0" cellpadding="1" cellspacing="0"
            style="border-collapse: collapse;">
            <tr>
              <td>
                <table border="0" cellpadding="0">
                  <tr>
                    <td align="center" colspan="2">Log In</td>
                  </tr>
                  <tr>
                    <td align="right" width="185">
                      <asp:Label ID="UserNameLabel" runat="server" 
                      AssociatedControlID="UserName">Username:</asp:Label>
                    </td>
                    <td>
                      <asp:TextBox ID="UserName" runat="server"></asp:TextBox>
                      <asp:RequiredFieldValidator ID="UserNameRequired" 
                      runat="server" ControlToValidate="UserName" 
                        ErrorMessage="User Name is required."
                        ToolTip="User Name is required." 
                        ValidationGroup="ExampleLogin">*</asp:RequiredFieldValidator>
                    </td>
                  </tr>
                  <tr>
                    <td align="right">
                      <asp:Label ID="PasswordLabel" runat="server" 
                      AssociatedControlID="Password">Password:</asp:Label>
                    </td>
                    <td>
                      <asp:TextBox ID="Password" runat="server" 
                      TextMode="Password"></asp:TextBox>
                      <asp:RequiredFieldValidator ID="PasswordRequired" 
                      runat="server" ControlToValidate="Password" 
                        ErrorMessage="Password is required."
                        ToolTip="Password is required." 
                        ValidationGroup="ExampleLogin">*</asp:RequiredFieldValidator>
                    </td>
                  </tr>
                  <tr>
                    <td></td>
                    <td>
                      <BotDetect:WebFormsCaptcha ID="LoginCaptcha" 
                      UserInputID="CaptchaCodeTextBox"
                      ImageSize="150, 50" CodeLength="3" runat="server" />
                    </td>
                  </tr>
                  <tr runat="server" id="CaptchaRow">
                    <td align="right">
                      <asp:Label ID="CaptchaLabel" runat="server" 
                      AssociatedControlID="CaptchaCodeTextBox">Code:</asp:Label>
                    </td>
                    <td>
                      <asp:TextBox ID="CaptchaCodeTextBox" runat="server"></asp:TextBox>
                      <asp:RequiredFieldValidator ID="CaptchaRequiredValidator" 
                      runat="server"
                        ControlToValidate="CaptchaCodeTextBox" 
                        ErrorMessage="CAPTCHA code is required."
                        ToolTip="CAPTCHA code is required." 
                        ValidationGroup="ExampleLogin">*</asp:RequiredFieldValidator>
                    </td>
                  </tr>
                  <tr>
                    <td align="center" colspan="2" style="color: Red;">
                      <span>
                        <asp:Literal ID="FailureText" runat="server" 
                        EnableViewState="False"></asp:Literal></span>
                    </td>
                  </tr>
                  <tr>
                    <td align="right" colspan="2">
                      <asp:Button ID="LoginButton" runat="server" 
                      CommandName="Login" Text="Log In"
                        ValidationGroup="ExampleLogin" />
                    </td>
                  </tr>
                </table>
              </td>
            </tr>
          </table>
        </LayoutTemplate>
      </asp:Login>
      <p><a href="Register.aspx">Register</a></p>
    </fieldset>
  </form>
</body>
</html>

The <BotDetect:WebFormsCaptcha> control is added to the Login form below the username and password fields. An <asp:RequiredFieldValidator> is added and connected with the Captcha code textbox, to warn users not to submit the form without entering the Captcha code.

Login.aspx.vb

Imports BotDetect.Web.UI

Partial Class Login
  Inherits System.Web.UI.Page

  Protected Sub ExampleLogin_Authenticate(ByVal sender As Object, 
  ByVal e As System.Web.UI.WebControls.AuthenticateEventArgs)
    Dim CaptchaCodeTextBox As TextBox = TryCast(ExampleLogin.FindControl(
    "CaptchaCodeTextBox"), TextBox)
    Dim LoginCaptcha As WebFormsCaptcha = TryCast(ExampleLogin.FindControl(
    "LoginCaptcha"), WebFormsCaptcha)

    'first, validate the Captcha to check we're not dealing with a bot
    If (Not IsHuman) Then
      Dim code As String, isHuman As Boolean
      code = CaptchaCodeTextBox.Text.Trim()
      isHuman = LoginCaptcha.Validate(code)
      CaptchaCodeTextBox.Text = "" ' clear previous user input

      If Not isHuman Then
        ExampleLogin.FailureText = "Retype the characters from the image carefully."
        e.Authenticated = False
        Return
      End If

      HideCaptcha() ' hide the CAPTCHA once it's solved

      'only when we're sure the visitor is human, we try to authenticate them
      If Not Membership.ValidateUser(ExampleLogin.UserName, ExampleLogin.Password) 
      Then
        ExampleLogin.FailureText = "Invalid login info."
        e.Authenticated = False

        FailedAuthAttempts = FailedAuthAttempts + 1
        If (ResetFailedAuthAttempts < FailedAuthAttempts) Then
          ' show the CAPTCHA again if the user enters invalid authentication
          ' info three times in a row
          ShowCaptcha()
        End If

        Return
      End If
    End If

    e.Authenticated = True
  End Sub

  Protected Sub HideCaptcha()
    Dim LoginCaptcha As WebFormsCaptcha = TryCast(ExampleLogin.FindControl(
    "LoginCaptcha"), WebFormsCaptcha)
    Dim CaptchaRow As HtmlControl = TryCast(ExampleLogin.FindControl("CaptchaRow")
    , HtmlControl)

    CaptchaRow.Visible = False
    LoginCaptcha.Visible = False
  End Sub

  Protected Sub ShowCaptcha()
    Dim LoginCaptcha As WebFormsCaptcha = TryCast(ExampleLogin.FindControl(
    "LoginCaptcha"), WebFormsCaptcha)
    Dim CaptchaRow As HtmlControl = TryCast(ExampleLogin.FindControl("CaptchaRow")
    , HtmlControl)

    IsHuman = False
    FailedAuthAttempts = 0
    CaptchaRow.Visible = True
    LoginCaptcha.Visible = True
  End Sub

  ' flag showing the user successfully passed the CAPTCHA test
  Protected Property IsHuman() As Boolean
    Get
      Dim result As Boolean = False
      Try
        If (Nothing <> Session("IsHuman")) Then
          result = CBool(Session("IsHuman"))
        End If
      Catch e As InvalidCastException
      End Try

      Return result
    End Get

    Set(ByVal value As Boolean)
      Session("IsHuman") = value
    End Set
  End Property

  Protected Const ResetFailedAuthAttempts As Integer = 3

  ' failed authentication attempt counter
  Protected Property FailedAuthAttempts() As Integer
    Get
      Dim count As Integer = 0
      Try
        If (Nothing <> Session("FailedAuthAttempts")) Then
          count = CInt(Session("FailedAuthAttempts"))
        End If
      Catch e As InvalidCastException
      End Try

      Return count
    End Get

    Set(ByVal value As Integer)
      Session("FailedAuthAttempts") = value
    End Set
  End Property

End Class

Since we want to process login attempts as they are submitted, we handle the ExampleLogin_Authenticate event. To get the Captcha code textbox and Captcha control instances, we have to use ExampleLogin.FindControl() calls (as they can't be accessed directly by ID in this event handler).

Since we want to remember when the user correctly solved the Captcha (so they don't have to immediately solve another one if the fail the first authentication attempt), we keep it in the IsHuman property wrapping Session persistence. And since we want to reset the Captcha status after a number of failed authentications (3 by default, as defined in the ResetFailedAuthAttempts constant), we keep the related counter in the FailedAuthAttempts property.

This allows us to implement the proper Login form workflow:

  • The user must first solve the Captcha to prove they are human. This keeps the bots away from the Membership provider, both conserving its resources and improving its security (since usernames and passwords will not be forwarded to the underlying data store if the Captcha is not solved first).
  • When the user has proven they are human, they get 3 authentication attempts without new Captcha tests, which allows them to remember the right combination in most cases.
  • If the user fails three authentication requests, they are shown a new Captcha which they must solve before continuing. This throttles authentication access, ensuring username + password combinations cannot be brute-forced, while real human users get theoretically unlimited authentication attempts (as long as they don't mind solving further Captchas).

Register.aspx

<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Register.aspx.vb" 
Inherits="Register" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>Register</title>
  <link type="text/css" rel="Stylesheet" href="StyleSheet.css" />
</head>
<body>
  <form id="form1" runat="server">
    <h1>BotDetect CAPTCHA ASP.NET Membership Example</h1>
    <fieldset>
      <legend>CAPTCHA Validation in a <code>CreateUserWizard</code> control</legend>
      <asp:CreateUserWizard ID="RegisterUser" runat="server"
        OnNextButtonClick="RegisterUser_NextButtonClick" ActiveStepIndex="0">
        <WizardSteps>
          <asp:CreateUserWizardStep runat="server">
            <ContentTemplate>
              <table border="0">
                <tr>
                  <td align="center" colspan="2">Sign Up for Your New Account</td>
                </tr>
                <tr>
                  <td align="right" width="185">
                    <asp:Label ID="UserNameLabel" runat="server" 
                    AssociatedControlID="UserName">Username:</asp:Label>
                  </td>
                  <td>
                    <asp:TextBox ID="UserName" runat="server"></asp:TextBox>
                    <asp:RequiredFieldValidator ID="UserNameRequired" 
                    runat="server" ControlToValidate="UserName" 
                      ErrorMessage="User Name is  required."
                      ToolTip="User Name is required." 
                      ValidationGroup="RegisterUser">*</asp:RequiredFieldValidator>
                  </td>
                </tr>
                <tr>
                  <td align="right">
                    <asp:Label ID="PasswordLabel" runat="server" 
                    AssociatedControlID="Password">Password:</asp:Label>
                  </td>
                  <td>
                    <asp:TextBox ID="Password" runat="server" 
                    TextMode="Password"></asp:TextBox>
                    <asp:RequiredFieldValidator ID="PasswordRequired" 
                    runat="server" ControlToValidate="Password" 
                      ErrorMessage="Password is required."
                      ToolTip="Password is required." 
                      ValidationGroup="RegisterUser">*</asp:RequiredFieldValidator>
                  </td>
                </tr>
                <tr>
                  <td align="right">
                    <asp:Label ID="ConfirmPasswordLabel" runat="server"
                      AssociatedControlID="ConfirmPassword">Confirm Password:</asp:Label>
                  </td>
                  <td>
                    <asp:TextBox ID="ConfirmPassword" runat="server" 
                    TextMode="Password"></asp:TextBox>
                    <asp:RequiredFieldValidator ID="ConfirmPasswordRequired" 
                    runat="server"
                      ControlToValidate="ConfirmPassword"
                      ErrorMessage="Confirm Password is required."
                      ToolTip="Confirm Password is required." 
                      ValidationGroup="RegisterUser">*</asp:RequiredFieldValidator>
                  </td>
                </tr>
                <tr>
                  <td align="center" colspan="2">
                    <asp:CompareValidator ID="PasswordCompare" runat="server"
                      ControlToCompare="Password" 
                      ControlToValidate="ConfirmPassword"
                      Display="Dynamic"
                      ErrorMessage="The Password and Confirmation Password must match."
                      ValidationGroup="RegisterUser"></asp:CompareValidator>
                  </td>
                </tr>
                <tr>
                  <td align="right">
                    <asp:Label ID="EmailLabel" runat="server" 
                    AssociatedControlID="Email">E-mail:</asp:Label>
                  </td>
                  <td>
                    <asp:TextBox ID="Email" runat="server"></asp:TextBox>
                    <asp:RequiredFieldValidator ID="EmailRequired" 
                    runat="server"
                      ControlToValidate="Email" ErrorMessage="E-mail is required. "
                      ToolTip="E-mail is required." 
                      ValidationGroup="RegisterUser">*</asp:RequiredFieldValidator>
                  </td>
                </tr>
                <tr>
                  <td></td>
                  <td>
                    <BotDetect:WebFormsCaptcha ID="RegisterCaptcha" 
                    UserInputID="CaptchaCodeTextBox"
                    ImageSize="150, 50" CodeLength="3" runat="server" />
                  </td>
                </tr>
                <tr>
                  <td align="right">
                    <asp:Label ID="CaptchaLabel" runat="server" 
                    AssociatedControlID="CaptchaCodeTextBox">Code:</asp:Label>
                  </td>
                  <td>
                    <asp:TextBox ID="CaptchaCodeTextBox" runat="server"></asp:TextBox>
                    <asp:RequiredFieldValidator ID="CaptchaRequiredValidator" 
                    runat="server"
                      ControlToValidate="CaptchaCodeTextBox" 
                      ErrorMessage="CAPTCHA code is required."
                      ToolTip="CAPTCHA code is required." 
                      ValidationGroup="RegisterUser">*</asp:RequiredFieldValidator>
                  </td>
                </tr>
                <tr>
                  <td align="center" colspan="2" style="color: Red;">
                    <span>
                      <asp:Literal ID="InvalidCaptchaInput" runat="server" 
                      EnableViewState="False" Visible="False" Text="Retype the 
                      characters from the image carefully."></asp:Literal></span>
                  </td>
                  <td align="center" colspan="2" style="color: Red;">
                    <span>
                      <asp:Literal ID="ErrorMessage" runat="server" 
                      EnableViewState="False"></asp:Literal></span>
                  </td>
                </tr>
              </table>
            </ContentTemplate>
          </asp:CreateUserWizardStep>
          <asp:CompleteWizardStep runat="server">
            <ContentTemplate>
              <table border="0">
                <tr>
                  <td align="center" colspan="2">Complete</td>
                </tr>
                <tr>
                  <td>Your account has been successfully created.</td>
                </tr>
                <tr>
                  <td align="right" colspan="2">
                    <p><a href="Default.aspx">Continue</a></p>
                  </td>
                </tr>
              </table>
            </ContentTemplate>
          </asp:CompleteWizardStep>
        </WizardSteps>
      </asp:CreateUserWizard>
      <p><a href="Login.aspx">Login</a></p>
    </fieldset>
  </form>
</body>
</html>

To protect the user registration field from automated submissions, a <BotDetect:WebFormsCaptcha> control is added to the CreateUserWizard template.

Register.aspx.vb

Imports BotDetect.Web.UI

Partial Class Register
  Inherits System.Web.UI.Page

  Protected Sub RegisterUser_NextButtonClick(ByVal sender As Object, 
  ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs)

    If e.CurrentStepIndex = 0 Then 'CreateUserStep

      ' get control references
      Dim RegisterCaptcha As WebFormsCaptcha = TryCast(RegisterUser.
      CreateUserStep.ContentTemplateContainer.FindControl("RegisterCaptcha"), 
      WebFormsCaptcha)
      Dim CaptchaCodeTextBox As TextBox = 
      TryCast(RegisterUser.CreateUserStep.ContentTemplateContainer.FindControl("CaptchaCodeTextBox"), TextBox)
      Dim CaptchaIncorrect As Literal = 
      TryCast(RegisterUser.CreateUserStep.ContentTemplateContainer.FindControl("InvalidCaptchaInput"), Literal)

      ' validate the Captcha to check we're not dealing with a bot
      Dim code As String, isHuman As Boolean
      code = CaptchaCodeTextBox.Text.Trim()
      isHuman = RegisterCaptcha.Validate(code)
      CaptchaCodeTextBox.Text = "" ' clear previous user input

      If Not isHuman Then
        CaptchaIncorrect.Visible = True
        e.Cancel = True
      Else
        CaptchaIncorrect.Visible = False
      End If
    End If

  End Sub
End Class

To process user creation attempts, we handle the RegisterUser_NextButtonClick event and make sure the code is executed during the first wizard step where Captcha protection was added (If e.CurrentStepIndex = 0).

We use ContentTemplateContainer.FindControl() calls to get all necessary control references, and simply cancel account creation unless Captcha validation succeeds.

Web.config

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="botDetect" requirePermission="false" 
    type="BotDetect.Configuration.BotDetectConfigurationSection, BotDetect"/>
  </configSections>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
    <add key="ValidationSettings:UnobtrusiveValidationMode" value="None" />
  </appSettings>
  <system.web>
    <httpHandlers>
      <!-- Register the HttpHandler used for BotDetect Captcha requests -->
      <add verb="GET" path="BotDetectCaptcha.ashx" 
      type="BotDetect.Web.CaptchaHandler, BotDetect"/>
    </httpHandlers>
    <!-- Register a custom SessionIDManager for BotDetect Captcha requests -->
    <sessionState mode="InProc" cookieless="AutoDetect" timeout="20" 
    sessionIDManagerType="BotDetect.Web.CustomSessionIdManager, BotDetect"/>
    <!-- Session state is required for BotDetect storage; you can also turn if 
    off globally and only enable for BotDetect-protected pages if you prefer -->
    <pages enableSessionState="true" controlRenderingCompatibilityVersion="4.5">
      <controls>
        <!-- Register the BotDetect tag prefix for easier use in all pages -->
        <add assembly="BotDetect" namespace="BotDetect.Web.UI" 
        tagPrefix="BotDetect"/>
      </controls>
      <namespaces>
        <add namespace="BotDetect"/>
        <add namespace="BotDetect.Web"/>
        <add namespace="BotDetect.Web.UI"/>
      </namespaces>
    </pages>
    <compilation debug="false" targetFramework="4.5" />
    <httpRuntime requestValidationMode="4.5" targetFramework="4.5" 
    encoderType="System.Web.Security.AntiXss.AntiXssEncoder, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <machineKey compatibilityMode="Framework45" />
    <trace enabled="false" localOnly="true"/>
    <httpCookies httpOnlyCookies="true"/>
    <trust level="Full" originUrl=""/>
    <customErrors mode="RemoteOnly"/>
    <!-- Forms authentication -->
    <authentication mode="Forms">
      <forms loginUrl="Login.aspx"/>
    </authentication>
    <!-- Deny access to all pages to unauthorized users -->
    <authorization>
      <deny users="?"/>
      <allow users="*"/>
    </authorization>
    <!-- Membership provider -->
    <membership defaultProvider="MockMembershipProvider">
      <providers>
        <add name="MockMembershipProvider" applicationName="/" 
        type="Sample.MockMembershipProvider"/>
      </providers>
    </membership>
  </system.web>
  <!-- Allow unauthorized access to the Login page -->
  <location path="Login.aspx">
    <system.web>
      <authorization>
        <allow users="*"/>
      </authorization>
    </system.web>
  </location>
  <!-- Allow unauthorized access to the Register page -->
  <location path="Register.aspx">
    <system.web>
      <authorization>
        <allow users="*"/>
      </authorization>
    </system.web>
  </location>
  <!-- Allow unauthorized access to BotDetect Captcha images and sounds -->
  <location path="BotDetectCaptcha.ashx">
    <system.web>
      <authorization>
        <allow users="*"/>
      </authorization>
    </system.web>
  </location>
  <!-- Allow unauthorized access to the Stylesheet -->
  <location path="StyleSheet.css">
    <system.web>
      <authorization>
        <allow users="*"/>
      </authorization>
    </system.web>
  </location>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <handlers>
      <!-- Register the HttpHandler used for BotDetect Captcha requests (IIS 7.0+) -->
      <remove name="BotDetectCaptchaHandler"/>
      <add name="BotDetectCaptchaHandler" preCondition="integratedMode" 
      verb="GET" path="BotDetectCaptcha.ashx" 
      type="BotDetect.Web.CaptchaHandler, BotDetect"/>
    </handlers>
  </system.webServer>
  <botDetect helpLinkEnabled="true" helpLinkMode="image" />
</configuration>

Besides the usual BotDetect-related web.config changes (Captcha HttpHandler registration, ASP.NET Session state configuration, and BotDetect tag prefix registration), the authentication and authorization elements define access restrictions, while the location elements specify exceptions to those restrictions. In this case, unauthorized users can only access the Login and Register pages and BotDetect Captcha paths.

To keep the example as simple as possible, we use the MockMembershipProvider instead of a real MembershipProvider. It doesn't access any data store to verify the user's credentials, but considers all authorization requests with usernames and passwords longer than 5 characters as valid. Since it doesn't affect Captcha protection and validation logic, MockMembershipProvider is not shown (but is included in the example installation).