Introduction To reCAPTCHA
Spam is a HUGE issue for websites. Scripted robots created by spammers crawl around the web constantly, trying to spam different form fields in hopes to get their spam messages out. Luckily there is an easy way to combat these spammers using a service called reCAPTCHA. reCAPTCHA is a free service provided by Google that attempts to detect legitimate visitors using a number of ever changing techniques. If it is unable to determine whether a visitor is legitimate or not, it asks the user to solve a simple puzzle to prove that they are human.
The image users get when they are known to be legitimate.
If reCAPTCHA has doubts the user is legitimate, it displays a puzzle like the one above after they check the I'm not a robot checkbox.
reCAPTCHA Site Setup
Before we can utilize reCAPTCHA in our application, we must first set up a new site. Sign into your Google account and visit the reCAPTCHA admin page.
You should see a page similar to the one listed above. Under the section labeled Register a new site fill in the label with a descriptive value. For the domains, list all applicable domains you will be using reCAPTCHA on. For example, if your website is example.com, make sure to list example.com. Also include localhost as well as any development, staging, or QA servers that you will use. For internal servers, simply use the internal IP for the domain. Once finished, click the Register button.
After clicking register, you will be taken to a page listing the site key and secret key. Make sure to take note of these values, you will need them later on.
Now we can work on our Rails application!
Rails Application Setup
This example will be a simple new user signup form that allows the user to provide a name, email address, and password to create a new account. This signup form is not unlike signup forms you've run into before on various websites. Our signup form will have the reCAPTCHA checkbox. To make integration easier, we will use the recaptcha gem. The recaptcha gem provides a few helpers that makes integration much easier.
First, we need to add the recaptcha gem to our
Gemfile. We also need to add in the bcrypt gem for the purposes of this example. If you are integrating reCAPTCHA into your own application, you don't need to add bcrypt. Open up your Gemfile and add in the lines listed below.
gem 'recaptcha', require: 'recaptcha/rails' gem 'bcrypt'
Now run a bundle install to install the gem.
Now we need to create an initializer to configure the
recaptcha gem. Create a new file in
recaptcha.rb and modify it so that it looks like the code listed below.
Recaptcha.configure do |config| config.site_key = Rails.application.secrets.recaptcha_site_key config.secret_key = Rails.application.secrets.recaptcha_secret_key end
In the above initializer, we set the site key and secret key to the values contained in the Rails
secrets.ymlunless you add your
secrets.ymlfile to your
.gitignorefile. Instead, use environment variables.
Now for the
config/secrets.yml file. In this example application, I am pulling the secret key and site key from environment variables. Open up your secrets.yml file and modify it to include your site key and secret.
# Be sure to restart your server when you modify this file. # Your secret key is used for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. # You can use `rails secret` to generate a secure secret key. # Make sure the secrets in this file are kept private # if you're sharing your code publicly. development: secret_key_base: 2f94601049a14193ca603923d770a0189c82d3746fbdb3aa472780791dc1e0c4048f473a1004a829a10d0aaa0abfc0f061282a51eba05af926849d772bac022a recaptcha_site_key: <%= ENV["RECAPTCHA_SITE_KEY"] %> recaptcha_secret_key: <%= ENV["RECAPTCHA_SECRET_KEY"] %> test: secret_key_base: 58150241e15c621ffba28e32cd67928e54a78dfe722371c3e52b740eb7ebb5c05a02cd10071b3661af6771d1aca8f41453f6315e807c61d3f8c5e8e1b8c7adb7 # Do not keep production secrets in the repository, # instead read values from the environment. production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> recaptcha_site_key: <%= ENV["RECAPTCHA_SITE_KEY"] %> recaptcha_secret_key: <%= ENV["RECAPTCHA_SECRET_KEY"] %> </code>
Great, now let's build out our example. This example app will contain a single model called User. The user model will contain three fields. The first,
name, is just a name for the user. The second,
password_digest, is used by bcrypt to store a salted and hashed password. If those terms are unclear to you, don't worry, it isn't necessary to understand them for this article. We will cover bcrypt and the terms mentioned in a future revised article about building authentication from scratch. For now, run the commands listed below to create your user model and migrate the database.
rails g model user name email password_digest rake db:migrate
Now we need to add some code to our user model. Once again, don't worry about the details. The important thing we are doing here is adding validations to demonstrate how reCAPTCHA works when the page is re-rendered. The
has_secure_password is a magic function that bcrypt provides to inject it's code into our model.
class User < ApplicationRecord has_secure_password validates_presence_of :password, on: :create validates :email, uniqueness: true, presence: true end
Now let's create a controller and our views. We will create a controller called Users with two actions,
new action will render the signup form, and the
create action will process it. Run the commands listed below to create the users controller now.
rails g controller users new create
Excellent, now let's change our routes file. Open up the
config/routes.rb file and modify it so that it looks like the code listed below.
Rails.application.routes.draw do resources :users, only: [:new, :create] root to: 'users#new' end
First, we specify that users a resource based controller. This just sets up some default routes for the
create actions. Second, we set the site root to automatically go to
/users/new. This is just for convenience.
Before we add code to our users controller, let's create our
users/new view first. Open up the
app/views/users/new.html.erb file and modify it so that it looks like the code listed below.
<h3>New User Sign Up</h3> <% if [email protected]? %> <ul> <% @user.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> <% end %> <%= form_for User.new do |f| %> <div> <%= f.label :name %> <%= f.text_field :name %> </div> <div> <%= f.label :email %> <%= f.text_field :email %> </div> <div> <%= f.label :password %> <%= f.password_field :password %> </div> <div> <%= f.label :password_confirmation %> <%= f.password_field :password_confirmation %> </div> <div> <br /> <%= recaptcha_tags %> <br /> </div> <div> <%= f.submit "Sign Up" %> </div> <% end %>
The form is a pretty standard form with the exception of line 28. line 28 calls a special helper provided by the
recaptcha gem. This helper sets everything up for using reCAPTCHA. Since we are editing views, let's create our
create view next. This view is only shown to the user if they have successfully submitted the form. Open up the
app/views/users/create.html.erb file and modify it so that it looks like the code listed below.
<h3>Thank You!</h3> <p> Thanks for signing up! </p>
Now for the final piece of the puzzle. Open up the users controller at
app/controllers/users_controller.rb and modify it so that it looks like the code listed below.
class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(user_params) if !verify_recaptcha(model: @user) || [email protected] render "new" end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end end
Line 8 calls another helper method provided by the
recaptcha gem called
verify_recaptcha method checks whether the reCAPTCHA information the user provided was valid. If it was not, the
new is rendered again with an error message that the
recaptcha gem provides. If reCAPTCHA returns success and the form is valid, the
create view gets rendered, which indicates success.
Thanks for reading!