【Rails】bcryptを使ってログイン機能を実装する方法

「bcrypt」はパスワードを安全に扱うためのgemパッケージです。

今回はそんなbcryptを使い、Railsでログイン機能を実装します。

1. bcryptをインストール

# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'

Gemfileの上の箇所のコメントアウトを外します。

Terminal window
bundle install

Bundlerでインストールしてあげます。

2. パスワード用のカラムを追加

Terminal window
bin/rails g migration AddUsers1

まずマイグレーションを生成。今回はUserにパスワードを設定したいので、User用のものを指定します。

class AddUsers1 < ActiveRecord::Migration[5.2]
def change
add_column :users, :password_digest, :string
end
end

Userテーブルにpassword_digestというカラムを追加します。パスワードを扱う際にはこの命名にする必要があります。

Terminal window
bin/rails db:migrate

そうしたらマイグレーションを実行してあげます。

You don’t have bcrypt installed ...

もし上のようなエラーが出た場合は、以下の記事を参考にしてください。

ruby/rails-bcrypt-not-installed)

3.「has_secure_password」を記述

class User < ApplicationRecord
has_secure_password
(省略)

User.rbhas_secure_passwordを追記します。これはパスワードを扱うためのおまじない的なものだと思ってもらえれば大丈夫です。

これによりpasswordpassword_confirmationという2つのカラムがUserクラスに追加されます。

ちなみにどちらもNOT NULLかつ同じ値、というバリデーションがデフォルトで設定されます。

4. パスワードを保存

Terminal window
User.create!(<省略>, password: <任意のパスワード>, password_confirmation: <任意のパスワード>)

Railsコンソールで実際に上の2つのカラムの値を指定し、保存できればOK。

5. コントローラーを作成

ログインのためのコントローラーを作ります。

resource :login ,only: [:create, :destroy]

まずroute.rbに上のように記述してあげます。

Terminal window
bin/rails g controller logins

次にloginsコントローラーを作ります。

class LoginsController < ApplicationController
def create # ログイン
user=User.find_by(login_id:params[:login_id])
if user && user&.authenticate(params[:password])
session[:user_id]=user.id
flash.alert="ログインに成功しました。"
else
flash.alert="ログインに失敗しました。"
redirect_to("/")
end
end
def destroy # ログアウト
session.delete(:user_id)
redirect_to("/")
end
end

次にLoginsControllerにログインとログアウトの処理を実装。

今回は簡易的なものですが、4行目でパスワードが合っているかをチェックし、5行目でセッションデータに値を入れログインを実現しています。

authenticatesメソッドは、引数で指定したパスワードが合っていればモデルオブジェクトを返してくれます。

6. フォームを実装

<%= form_tag :session, id:"login_form" do %>
<div>
<label>id:</label>
<input type="text" name="login_id">
</div>
<div>
<label>パスワード</label>
<input type="text" name="password">
</div>
<div>
<input type="submit" value="ログイン">
</div>
<%end%>

erbファイルにて、LoginsControllerで必要なログインIDとパスワードを入力するフォームを実装します。

7. ログイン中のユーザーを取得

class ApplicationController < ActionController::Base
private def current_user
if session[:user_id]
User.find_by(id:session[:user_id])
end
end
(省略)

ログインユーザー(ログイン状態)を取得するcurrent_userメソッドをapplication_controllerに実装。これで全てのコントローラーでログイン状態を取得できます。

8. ログイン状態を表示

<%if current_user%>
<%="#{current_user.name}さん"%>
<%=link_to("ログアウト",:login,method: :delete,data:{confirm:"本当にログアウトしますか?"})%>
<%end%>

適当なerbファイルを作成し、ログインしている場合にユーザー名とログアウトボタンを表示するようにします。

適当なログインIDとパスワードを入力する

適当なログインIDとパスワードを入力すると⋯

無事ログインできました

ユーザー名が表示され、無事ログインできました。