Angular Form CAPTCHA Code Example

  1. Client-side
    1. Angular 2/4/5/6/7+
    2. AngularJS 1.x
  2. Server-side

I. Client-side

a) Angular 2/4/5/6/7+

The Angular Form Captcha code example shows how to add BotDetect CAPTCHA protection to a typical Angular form.

Captcha validation is integrated with other form fields validation, and only submissions that meet all validation criteria are accepted.

This kind of validation could be used on various types of public forms which accept messages, and are at risk of unwanted automated submissions.

For example, it could be used to ensure bots can't submit anything to a contact form, add guestbook entries, blog post comments or anonymous message board / forum replies.

Download the BotDetect ASP.NET CAPTCHA Library and run this example

Installed Location

By default, the Angular Form CAPTCHA code example project is installed at:
C:\Program Files\Captcha Inc\BotDetect 4 CAPTCHA Component\Asp.Net\.NET\WebApp\SimpleAPI\AngularCaptchaExample

You can also run it from the BotDetect Start Menu:
Programs > Captcha Inc > BotDetect 4 CAPTCHA Component > ASP.NET > ASP.NET Examples > Run .NET Examples

app.module.ts

import { NgModule } from '@angular/core';
  import { BrowserModule } from '@angular/platform-browser';
  import { FormsModule, ReactiveFormsModule } from '@angular/forms';
  import { HttpModule } from '@angular/http';
  
  import { AppRoutingModule } from './app-routing.module';
  import { BotDetectCaptchaModule } from 'angular-captcha';
  
  import { AppComponent } from './app.component';
  import { ContactComponent }   from './contact/contact.component';
  
  import { ValuesPipe } from './values.pipe';
  
  @NgModule({
    imports: [
      BrowserModule,
      FormsModule,
      HttpModule,
      ReactiveFormsModule,
      AppRoutingModule,
      BotDetectCaptchaModule.forRoot({
        captchaEndpoint: 'BotDetectCaptcha.ashx',
      })
    ],
    declarations: [
      AppComponent,
      ContactComponent,
      ValuesPipe
    ],
    providers: [],
    bootstrap: [AppComponent]
  })
  export class AppModule { }
  

We import BotDetectCaptchaModule, then declare it in metadata imports of NgModule and configure BotDetect ASP.NET Captcha path in captchaEndpoint settings.

contact.component.html

<form novalidate (ngSubmit)="send(contact)" [formGroup]="contact">

  <div class="alert alert-success" *ngIf="successMessages">
    {{ successMessages }}
  </div>

  <div class="alert alert-error" *ngIf="errorMessages">
    <ul class="list-messages">
      <li *ngFor="let error of errorMessages | values">
        {{ error }}
      </li>
    </ul>
  </div>

  <label>
    <span>Name:</span>
    <input
      type="text"
      name="name"
      formControlName="name">
  </label>

  <div
    class="error"
    *ngIf="contact.get('name').hasError('minlength') && contact.get('name').touched"
    >
    Name must be at least 3 characters.
  </div>


  <label>
    <span>Email:</span>
    <input
      type="email"
      name="email"
      formControlName="email">
  </label>

  <div
    class="error"
    *ngIf="contact.get('email').hasError('pattern') && contact.get('email').touched"
    >
    Email is invalid.
  </div>


  <label>
    <span>Subject:</span>
    <input
      type="text"
      name="subject"
      formControlName="subject">
  </label>

  <div
    class="error"
    *ngIf="contact.get('subject').hasError('minlength') && contact.get('subject').touched"
    >
    Subject must be at least 10 characters.
  </div>


  <label>
    <span>Message:</span>
    <textarea
      name="message"
      formControlName="message"></textarea>
  </label>

  <div
    class="error textarea-error"
    *ngIf="contact.get('message').hasError('minlength') && contact.get('message').touched"
    >
    Message must be at least 10 characters.
  </div>
  
  <!-- show captcha html -->
  <botdetect-captcha styleName="angularFormCaptcha"></botdetect-captcha>

  <label>
    <span>Retype the characters from the picture:</span>
    <input
      type="text"
      id="captchaCode"
      name="captchaCode"
      formControlName="captchaCode"
      >
  </label>

  <button type="submit">Send</button>
</form>

Adding Captcha protection to the Angular form is as simple as using botdetect-captcha element, which is provided by BotDetect Captcha Angular Module and set to styleName attribute a Captcha style name defined in botdetect.xml configuration file below.

Beside the captcha code input field, the example form contains three other fields which are going to be validated in contact.component.ts later.

contact.component.ts

import { Component, ViewChild, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Observable } from 'rxjs/Rx';

import { CaptchaComponent } from 'angular-captcha';

import { Contact } from './contact.interface';
import { ContactService } from './contact.service';

@Component({
  moduleId: module.id,
  selector: 'contact-form',
  templateUrl: 'contact.component.html',
  styleUrls: ['contact.component.css'],
  providers: [ContactService]
})
export class ContactComponent implements OnInit {
  
  contact: FormGroup;

  emailRegex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

  /**
   * Captcha validation messages.
   */
  errorMessages: Object;
  successMessages: string;

  /**
   * BotDetect CAPTCHA component.
   */
  @ViewChild(CaptchaComponent) captchaComponent: CaptchaComponent;

  constructor(
    private fb: FormBuilder,
    private contactService: ContactService
  ) { }

  ngOnInit(): void {
    this.contact = this.fb.group({
      name: ['', [Validators.required, Validators.minLength(3)]],
      email: ['',  [Validators.required, Validators.pattern(this.emailRegex)]],
      subject: ['',  [Validators.required,Validators.minLength(10)]],
      message: ['',  [Validators.required,Validators.minLength(10)]],
      captchaCode: [''] // we use 'validateUnsafe' method to validate captcha code control when form is submitted
    });
  }

  send({ value }: { value: Contact }): void {

    // use validateUnsafe() method to perform client-side captcha validation
    this.captchaComponent.validateUnsafe((isCaptchaCodeCorrect: boolean) => {

      if (isCaptchaCodeCorrect && this.contact.controls.name.valid && this.contact.controls.email.valid
            && this.contact.controls.subject.valid && this.contact.controls.message.valid) {

        // form is valid
        // we send contact data as well as captcha data to server-side for
        // validating once again before they are inserted into database

        let postData = {
          name: value.name,
          email: value.email,
          subject: value.subject,
          message: value.message,
          captchaCode: this.captchaComponent.captchaCode,
          captchaId: this.captchaComponent.captchaId
        };
    
        this.contactService.send(postData)
          .subscribe(
            response => {
              if (response.success) {
                // captcha validation passed at server-side
                this.successMessages = 'CAPTCHA validation passed.';
                this.errorMessages = null;
              } else {
                // captcha validation failed at server-side
                this.errorMessages = response.errors;
                this.successMessages = '';
              }
    
              // always reload captcha image after validating captcha at server-side 
              // in order to update new captcha code for current captcha id
              this.captchaComponent.reloadImage();
            },
            error => {
              throw new Error(error);
            });
            
      } else {
        this.errorMessages = { formInvalid: 'Please enter valid values.' }
        this.successMessages = '';
      }
    });

  }
}

In the code above, we inject CaptchaComponent into ContactComponent using @ViewChild.

To validate Captcha code once at server-side api, we need to send both captcha id (via captchaComponent.captchaId property) and captcha code visitor submited (via captchaComponent.captchaCode property) to server-side.

Once request finished, we always reload Captcha by calling the reloadImage() function of CaptchaComponent. This is needed to generate the new captcha code for the current captcha id.

contact.service.ts

import { Injectable }    from '@angular/core';
  import { Http, Response, Headers, RequestOptions } from '@angular/http';
  
  import { Observable } from 'rxjs/Rx';
  
  @Injectable()
  export class ContactService {
  
    // contact api url
    contactUrl = 'ContactHandler.ashx';
  
    constructor(private http: Http) { }
  
    send(data: Object): Observable<any> {
      const headers = new Headers({ 'Content-Type': 'application/json' });
      const options = new RequestOptions({ headers: headers });
  
      return this.http.post(this.contactUrl, data, options)
        .map((response: Response) => response.json())
        .catch((error:any) => Observable.throw(error.json().error));
    }
  }
  

In this ContactService, we simply add a function that posts data to the contact api url using Http post of HttpModule.

contact.interface.ts

export interface Contact {
    name: string;
    email: string;
    subject: string;
    message: string;
    captchaCode: string;
  }
  

We implement this interface to use in contact.component.ts.

b) AngularJS 1.x

The AngularJS Form Captcha code example shows how to add BotDetect CAPTCHA protection to a typical AngularJS form.

Captcha validation is integrated with other form fields validation, and only submissions that meet all validation criteria are accepted.

This kind of validation could be used on various types of public forms which accept messages, and are at risk of unwanted automated submissions.

For example, it could be used to ensure bots can't submit anything to a contact form, add guestbook entries, blog post comments or anonymous message board / forum replies.


Download the BotDetect ASP.NET CAPTCHA Library and run this example

Installed Location

By default, the AngularJS Form CAPTCHA code example project is installed at:
C:\Program Files\Captcha Inc\BotDetect 4 CAPTCHA Component\Asp.Net\.NET\WebApp\SimpleAPI\AngularJSCaptchaExample

You can also run it from the BotDetect Start Menu:
Programs > Captcha Inc > BotDetect 4 CAPTCHA Component > ASP.NET > ASP.NET Examples > Run .NET Examples

contact-captcha.html

<form name="contactForm" novalidate ng-controller="ContactController" ng-submit="send(contactForm.$valid)" >
    
    <div class="alert alert-success" ng-show="successMessages">
      {{ successMessages }}
    </div>
  
    <div class="alert alert-error" ng-show="errorMessages">
      <ul class="list-messages" ng-repeat="(field, message) in errorMessages">
        <li>{{ message }}</li>
      </ul>
    </div>
    
    
    <label>
      <span>Name:</span>
      <input type="text" name="name" ng-model="name" ng-minlength="3">
    </label>
    
    <div class="error" ng-show="contactForm.name.$error.minlength && !contactForm.name.$pristine">
      Name must be at least 3 characters.
    </div>
    
    
    <label>
      <span>Email</span>
      <input type="email" name="email" ng-model="email" required>
    </label>
    
    <div class="error" ng-show="contactForm.email.$invalid && !contactForm.email.$pristine">
      Email is invalid.
    </div>
    
  
    <label>
      <span>Subject:</span>
      <input type="text" name="subject" ng-model="subject" ng-minlength="10">
    </label>
    
    <div class="error" ng-show="contactForm.subject.$error.minlength">
      Subject must be at least 10 characters.
    </div>
    
    
    <label>
      <span>Message:</span>
      <textarea name="message" ng-model="message" ng-minlength="10"></textarea>
    </label>
    
    <div class="error" ng-show="contactForm.message.$error.minlength">
      Message must be at least 10 characters.
    </div>
    
    
    <!-- show Captcha image html-->
    <botdetect-captcha styleName="angularFormCaptcha"></botdetect-captcha>
    
    <label>
      <span>Retype the characters from the picture:</span>
      <!-- captcha code user input textbox -->
      <input type="text" name="captchaCode" ng-model="captchaCode" correct-captcha id="captchaCode" autocomplete="off">
    </label>
  
    <button type="submit" class="btn btn-primary">Send</button>
  </form>
  

Adding Captcha protection to the AngularJS form is as simple as using botdetect-captcha element, which is provided by BotDetect Captcha AngularJS Module and set to styleName attribute a Captcha style name defined in botdetect.xml configuration file below.

Beside the captcha code input field, the example form contains three other fields which are validated using AngularJS directive validation.

app.js

var app = angular.module('app', ['BotDetectCaptcha']);

app.config(function($routeProvider, captchaSettingsProvider) {
  captchaSettingsProvider.setSettings({
    // declare your captcha endpoint, it will be served for getting captcha html, reload icon, sound icons, etc.
    captchaEndpoint: 'BotDetectCaptcha.ashx'
  });
});

app.controller('ContactController', function($scope, $http, Captcha) {
  // captcha validation messages
  $scope.successMessages = '';
  $scope.errorMessages = '';
  
  // contact url
  var contactUrl = 'ContactHandler.ashx';

  $scope.send = function(contactForm) {

    // create new BotDetect Angular Captcha instance
    var captcha = new Captcha();

    captcha.validateUnsafe(function(isCaptchaCodeCorrect) {
      
      if (isCaptchaCodeCorrect && contactForm.name.$valid && contactForm.email.$valid 
            && contactForm.subject.$valid && contactForm.message.$valid) {
    
        // after UI form validation passed, 
        // we will need to validate captcha at server-side before we save form data in database, etc.

        // captcha id for validating captcha at server-side
        var captchaId = captcha.captchaId;
        
        // captcha code input value for validating captcha at server-side
        var captchaCode = $scope.captchaCode;
        
        var postData = {
          name: $scope.name,
          email: $scope.email,
          subject: $scope.subject,
          message: $scope.message,
          captchaId: captchaId,
          captchaCode: captchaCode
        };
        
        $http({
          method: 'POST',
          url: contactUrl,
          data: JSON.stringify(postData)
        })
          .then(function(response) {
            if (response.data.success) {
              // captcha, other form data passed and the data is also stored in database
              // show success message
              $scope.successMessages = 'Your message was sent successfully!';
              $scope.errorMessages = null;
            } else {
              // form validation failed
              $scope.errorMessages = response.data.errors;
              $scope.successMessages = null;
            }
            
            // always reload captcha image after validating captcha at server-side 
            // in order to update new captcha code for current captcha id
            captcha.reloadImage();
          }, function(error) {
            console.log(error.data);
          });
      } else {
        $scope.errorMessages = { formInvalid: 'Please enter valid values.' };
        $scope.successMessages = null;
      }
    });
  };
  
});

First, we add BotDetectCaptcha to the app module as a dependency and configure BotDetect ASP.NET Captcha path to captchaEndpoint settings in config function.

In the code above, we inject Captcha into ContactController.

On form submit, we use validateUnsafe() method to perform client-side captcha validation and we also need to send captchaId property of Captcha object and captcha code visitors submitted to server-side to validate Captcha code once.

Once request finished, we always reload Captcha by calling reloadImage() function of Captcha object. This is needed to generate the new captcha code for the current captcha id.

II. Server-side

botdetect.xml

<?xml version="1.0" encoding="UTF-8"?>
  <botdetect xmlns="https://captcha.com/schema/net"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="https://captcha.com/schema/net
       https://captcha.com/schema/net/botdetect-4.4.0.xsd">
  
    <captchaStyles>
      <captchaStyle>
        <name>angularFormCaptcha</name>
        <userInputID>captchaCode</userInputID>
        <codeLength>4-6</codeLength>
        <codeStyle>Alphanumeric</codeStyle>
      </captchaStyle>
    </captchaStyles>
  
  </botdetect>
  

In botdetect.xml, we configure some captcha options for our angularjs basic captcha. You can find a full list of available SimpleCaptcha configuration options and related instructions at the SimpleCaptcha configuration options page.

ContactHandler.ashx

<%@ WebHandler Language="C#" Class="ContactHandler" %>

using System;
using System.Web;
using System.IO;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using BotDetect.Web;


public class ContactHandler : IHttpHandler
{

    public void ProcessRequest (HttpContext context)
    {

        if (HttpContext.Current.Request.HttpMethod == "POST")
        {
            string dataJson = new StreamReader(context.Request.InputStream).ReadToEnd();

            Dictionary<string, string> formDataObj = new Dictionary<string, string>();
            formDataObj = JsonConvert.DeserializeObject<Dictionary<string, string>>(dataJson);

            string name = formDataObj["name"];
            string email = formDataObj["email"];
            string subject = formDataObj["subject"];
            string message = formDataObj["message"];

            string captchaId = formDataObj["captchaId"];
            string captchaCode = formDataObj["captchaCode"];

            // validate captcha
            Dictionary<string, string> errors = new Dictionary<string, string>();

            if (!IsValidName(name))
            {
                errors.Add("name", "Name must be at least 3 characters.");
            }

            if (!IsValidEmail(email))
            {
                errors.Add("email", "Email is invalid.");
            }

            if (!IsValidSubject(subject))
            {
                errors.Add("subject", "Subject must be at least 10 characters.");
            }

            if (!IsValidMessage(message))
            {
                errors.Add("message", "Message must be at least 10 characters.");
            }

            if (!IsCaptchaCorrect(captchaCode, captchaId))
            {
                errors.Add("captchaCode", "CAPTCHA validation failed.");
            }


            bool isErrorsEmpty = errors.Count > 0 ? false : true;

            if (isErrorsEmpty)
            {
                // everything is ok
                // TODO: Insert form data into your database
            }

            // the object that stores validation result
            Dictionary<string, object> validationResult = new Dictionary<string, object>();
            validationResult.Add("success", isErrorsEmpty);
            validationResult.Add("errors", errors);

            // write the validation result as json string for sending it back to client
            context.Response.ContentType = "application/json; charset=utf-8";
            context.Response.Write(JsonConvert.SerializeObject(validationResult));
        }
        else
        {
            context.Response.ContentType = "text/plain";
            context.Response.Write("HTTP GET request is not allowed.");
        }

    }

    // validate function
    private bool IsCaptchaCorrect(string captchaCode, string captchaId)
    {
        SimpleCaptcha captcha = new SimpleCaptcha();
        return captcha.Validate(captchaCode, captchaId);
    }

    private bool IsValidName(string name)
    {
        if (name == null)
        {
            return false;
        }

        return (name.Length >= 3);
    }

    private bool IsValidEmail(string email)
    {
        if (email == null)
        {
            return false;
        }
        Regex regex = new Regex("^[\w-_\.+]*[\w-_\.]\@([\w]+\.)+[\w]+[\w]$");
        Match match = regex.Match(email);

        return match.Success;
    }

    private bool IsValidSubject(string subject)
    {
        if (subject == null)
        {
            return false;
        }

        return (subject.Length > 9) && (subject.Length < 255);
    }

    private bool IsValidMessage(string message)
    {
        if (message == null)
        {
            return false;
        }

        return (message.Length > 9) && (message.Length < 255);
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

}

At server-side api, we will get captchaId and captchaCode values sent from client-side and use Validate(captchaCode, captchaId) method of SimpleCaptcha instance to validate Captcha code. Finally, we write the validation result as json string for sending it back to client.

Please Note

Angular Captcha Module requires the new experimental Simple API that is currently available in BotDetect Java v4.0.Beta3+, BotDetect PHP v4.2.0+, as well as in BotDetect ASP.NET v4.4.0 build for legacy .NET.
The Simple API for ASP.NET Core will be available in the BotDetect ASP.NET v4.4.1 that will be released in few weeks time.