Vonage Verify APIを利用して2FAが組み込まれたRailsアプリケーションを実装します。
今回紹介するサンプルアプリケーションは公式のチュートリアルをベースとしているので、あわせてご覧になってください。
目次
事前準備
アカウント作成
Vonage Verify APIをはじめとしたVonageのコミュニケーションAPIを利用するには事前にアカウントを作成する必要があります。
Vonageのアカウント作成はこちらから行います。
Gemのインストール
必要となるGemをインストールします。
Gemfile
gem 'devise' # ユーザー認証で利用
gem 'vonage' # Vonage APIを利用する際に利用
gem 'dotenv-rails' # 環境変数ファイル作成で利用
2FAを行うユーザーをアプリケーションに登録する
Deviseのセットアップ
Deviseのセットアップを行います。Deviseの利用方法の詳細解説はdeviseのインストール手順をシンプルなログイン機能の実装で理解するで紹介しています。
Deviseのジェネレータを実行します。
$ rails generate devise:install
ルートURLを作成します。
routes.rb
root to: 'kittens#index'
コントローラーを作成します。
$ rails g controller Kittens index
ユーザーモデルを作成します。
$ rails g devise User
マイグレーションを実行します。
$ rails db:migrate
以下のようなユーザーテーブルが作成できていればOKです。
> describe users;
+------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+--------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| email | varchar(255) | NO | UNI | | |
| encrypted_password | varchar(255) | NO | | | |
| reset_password_token | varchar(255) | YES | UNI | NULL | |
| reset_password_sent_at | datetime | YES | | NULL | |
| remember_created_at | datetime | YES | | NULL | |
| created_at | datetime(6) | NO | | NULL | |
| updated_at | datetime(6) | NO | | NULL | |
+------------------------+--------------+------+-----+---------+----------------+
ユーザーを作成する
localhost:3000/users/sign_up
にアクセスし、ユーザーを作成します。
ユーザー情報に電話番号を追加する
2FAで必要になる電話番号をユーザー情報に追加します。
マイグレーションファイルを作成します。
$ rails generate migration add_phone_number_to_users
マイグレーションファイルは以下の通りです。
class AddPhoneNumberToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :phone_number, :string
end
end
マイグレーションを実行します。
$ rails db:migrate
phone_number
カラムが追加されていればOKです。
> describe users;
+------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+--------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| email | varchar(255) | NO | UNI | | |
| encrypted_password | varchar(255) | NO | | | |
| reset_password_token | varchar(255) | YES | UNI | NULL | |
| reset_password_sent_at | datetime | YES | | NULL | |
| remember_created_at | datetime | YES | | NULL | |
| created_at | datetime(6) | NO | | NULL | |
| updated_at | datetime(6) | NO | | NULL | |
| phone_number | varchar(255) | YES | | NULL | |
+------------------------+--------------+------+-----+---------+----------------+
電話番号をユーザー編集画面から更新できるようにする
ユーザー編集画面に電話番号を登録するフィールドを追加します。
app/views/devise/registrations/edit.html.erb
<div>
<%= f.label :phone_number %> <i>(Leave blank to disable two factor authentication)</i><br />
<%= f.number_field :phone_number, class: "form-control", placeholder: "e.g. 447555555555 or 1234234234234" %>
</div>
phone_number
が更新できるようにapplication_controller.rb
を編集します。
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# アプリケーションにアクセスする際は認証を行う
before_action :authenticate_user!
# deviseに関するリクエストの場合、phone_numberの更新を許可
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:account_update, keys: [:phone_number])
end
end
ログインユーザーの電話番号を更新する
http://localhost:3000/users/edit
にアクセスし、ログインユーザーに電話番号の情報を追加します。
電話番号のフォーマットはE.164にする必要があります。
E.164の場合、例えば日本の09012345678
という携帯電話番号は、先頭の0
を取り国番号の+81
をつけた+819012345678
となります。
Vonage APIを組み込み、2FAを実装する
RailsアプリケーションにVonage APIを組み込んでいきます。
APIキーとAPIシークレットの設定
Vonage Verify APIを利用する際に必要となるAPIキーとAPIシークレットを確認します。
APIキーとAPIシークレットはダッシュボード画面で確認できます。
環境変数の設定
APIキーとAPIシークレットを.env
ファイルに登録します。
.env
VONAGE_API_KEY=your_api_key
VONAGE_API_SECRET=your_api_secret
間違ってリモートリポジトリに環境変数を公開しないように.gitignore
に.env
を追加しておくとよいでしょう。
.gitignore
.env
以下のようにして確認して値が表示されればOKです。
$ rails c
> ENV['VONAGE_API_KEY']
# APIキーが表示されればOK
> ENV['VONAGE_API_SECRET']
# APIシークレットが表示されればOK
2FA実施前のチェック処理
今回のアプリケーションでは、2FAを実行する条件は「認証画面(deviseに関連する画面)以外にアクセスする場合 かつ 2FAが完了していない場合 かつ 電話番号が登録されている場合」とします。
devise(認証)に関する画面以外にアクセスした場合のみ、2FAを実行するようにします。
app/controllers/application_controller.rb
before_action :verify_user!, unless: :devise_controller?
def verify_user!
start_verification if requires_verification?
end
今回、2FAが完了しているかどうかの判定はセッションを利用します。
session[:verified]
が存在していない(2FAが完了していない) かつ 電話番号が存在している場合は2FAを実施するようにします。
app/controllers/application_controller.rb
def requires_verification?
session[:verified].nil? && !current_user.phone_number.blank?
end
2FAの実装: 認証コードの送信
2FAのプロセスには「認証コードの送信」と「入力された認証コードの検証」の2ステップがあります。
Vonage Verify APIを利用した「認証コードの送信」の実装は以下のようになります。
app/controllers/application_controller.rb
def start_verification
result = Vonage::Client.new.verify.request(
number: current_user.phone_number,
brand: "Kittens and Co",
sender_id: 'Kittens'
)
if result['status'] == '0'
redirect_to edit_verification_path(id: result['request_id'])
else
sign_out current_user
redirect_to :new_user_session, flash: {
error: 'Could not verify your number. Please contact support.'
}
end
end
2FAの実装: 入力された認証コードの検証
認証コードを入力するためのルーティングを追加します。
routes.rb
resources :verifications, only: [:edit, :update]
認証コードの入力画面を作成します。
$ rails g controller Verifications edit update
app/views/verifications/edit.html.erb
<div class="panel panel-default devise-bs">
<div class="panel-heading">
<h4>Verify code</h4>
</div>
<div class="panel-body">
<%= form_tag verification_path(id: params[:id]), method: :put do %>
<div class="form-group">
<%= label_tag :code %><br />
<%= number_field_tag :code, class: "form-control" %>
</div>
<%= submit_tag 'Verify', class: "btn btn-primary" %>
<% end %>
</div>
</div>
<%= link_to 'Send me a new code', :root %>
画面から入力されたパラメータを受け取り、Vonage Verify APIによる検証をします。
def update
confirmation = Vonage::Client.new.verify.check(
request_id: params[:id],
code: params[:code]
)
if confirmation['status'] == '0'
session[:verified] = true
redirect_to :root, flash: { success: 'Welcome back.' }
else
redirect_to edit_verification_path(id: params[:id]), flash[:error] = confirmation['error_text']
end
end
動作確認
電話番号の登録後、ホーム画面にアクセスするとデバイスに認証コードが送られます。
デバイスに送られてきた認証コードを入力します。
http://localhost:3000/
にリダイレクトされればOKです。
参考: Rails コンソールで2FAを確認する方法
Railsコンソール上でVonage Verify APIの2FAを確認する場合は以下のようになります。
$ rails c
### Vonage API Clientの作成
> client = Vonage::Client.new(api_key: 'YOUR--KEY', api_secret: 'YOUR-API-SECRET')
### 認証コードの送信
> result = client.verify.request(
number: '+81xxxx', # E.164フォーマットで記載した電話番号
brand: "Kittens and Co",
sender_id: 'Kittens'
)
> result["status"]
=> "0" # OK
### 認証コードの検証
> confirmation = client.verify.check(
request_id: result["request_id"],
code: 'xxx' # SMSで送られたコード
)
> confirmation["status"]
=> "0" # OK
さいごに
今回紹介したサンプルアプリケーションはGitHubのnishina555/vonage-rails-devise-2fa-demoに公開しました。
Dockerを導入しているので、docker-compose up
をするだけでアプリケーションが立ち上がり、2FAの確認ができるようになっています。
docker-compose up
のみでRailsアプリケーションを起動できるDocker環境の構築手順はチームで共有するための『Rails 6 x MySQL 8』Docker環境構築手順で紹介しています。
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!