フラッシュメッセージを含めたアカウントロック実装方法(gem Sorceryを使用)

投稿者
米村

こんにちは!開発部の米村です。

クライアントとお話する中で、やはり不正ログインによる個人情報漏洩については特に懸念ポイントであると感じる今日このごろ。

対策方法としては、「特定回数ログインに失敗した場合は、一定時間アカウントをロックする」 というアカウントロックが挙げられますね。

今回は、gem Sorceryを使って、アカウントロック機能が簡単に実装できることを紹介します!

Sorcery 公式Githubの「Brute force protection」をベースとし、ロックの有無によるフラッシュメッセージの切り替えもしていきます!

参考記事: Brute force protection

前提条件

下記のSorcery 公式Githubの通り、ログイン認証機能が実装されていることを前提とさせていただきます。

参考記事: Simple Password Authentication

実装

1.「Brute force protection」の設定追加

下記3つを修正しましょう。

# config/initializers/sorcery.rb

Rails.application.config.sorcery.submodules = [:brute_force_protection]
## submodulesにbrute_force_protectionを追加し、この機能を使用できるよう設定追加。

user.consecutive_login_retries_amount_limit = 5
## 何回ログインに失敗したら、アカウントをロックするか回数を設定。今回は、5回とします。

user.login_lock_time_period = 3600
## アカウントロックを解除するまでの時間を設定。今回は、60分とします。

2. Usersテーブルにカラムを追加

下記3つのカラムを追加します。

  • ridgepoleを使用している場合
# db/users.schema

  t.integer "failed_logins_count", default: 0
  t.datetime "lock_expires_at"
  t.string "unlock_token"
  • migrationファイルを使用している場合
 # db/migrate/*****_sorcery_brute_force_protection.rb
 
 class SorceryBruteForceProtection < ActiveRecord::Migration
   def self.up
     add_column :users, :failed_logins_count, :integer, default: 0
     add_column :users, :lock_expires_at, :datetime, default: nil
     add_column :users, :unlock_token, :string, default: nil
   end
 
   def self.down
     remove_column :users, :lock_expires_at
     remove_column :users, :failed_logins_count
     remove_column :users, :unlock_token
   end
 end    

3. 既存のログイン機能にアカウントロック時のフラッシュメッセージを追加

ログイン失敗時の部分で、フラッシュメッセージの条件分けを書くことで、コードが理解しやすくなりましたね。

# app/controllers/sessions_controller.rb

class SessionsController < ApplicationController

  def new
    @user = User.new
  end

  def create
    if login(user_params[:email], user_params[:password])
      return redirect_back_or_to root_path, notice: 'ログインしました。'
    end

    user = User.find_by(email: user_params[:email])
    ## アカウントロック時は、loginメソッドがnilを返すので、別途対象のuserを取得する必要があります。

    flash.now[:notice] = if user && user.login_locked?
    ## login_locked? はsorceryのメソッドであり、追加したカラム "failed_logins_count"が、アカウントロック回数に至っているuserであるかどうかを確認できます。
                           'ご利用のアカウントはロックされています。時間をおいて再度ログインしてください。'
                         else
                           'ログインに失敗しました。'
                         end
    render :new
  end

  private

  def user_params
    params.require(:user).permit(:email, :password)
  end
end

確認方法

実装が成功しているかrailsコンソールで確認したいと思います。確認用に、ロックまでの回数を2回、解除までの時間を1分とします。

# config/initializers/sorcery.rb

user.consecutive_login_retries_amount_limit = 2
user.login_lock_time_period = 60
  • パスワードがロックされていない状態(ログインに1回失敗)

画像

  • パスワードがロックされている状態(ログインに2回失敗)

画像

フラッシュメッセージが変更されることも確認してくださいね! 以上です!

一緒にスタートアップを盛り上げませんか?
RailsAPIモードとNuxtの組みわせでハマったこと
2019/12/25
こわくないよ!SQL 〜本番DBのデータが見たい!の巻〜
2020/02/07