Try T.M Engineer Blog

「アウトプットする事は大事だ」と思って初めたブログ、プログラミング、独り語り、etc

BCryptLibを使ってログイン画面を実装

学びシリーズ第2弾です。

作ってみた機能

BCryptライブラリを使ってログイン画面を実装

環境構成

全体構成・完成イメージ

f:id:special-moucom:20180430175646p:plain

[DB]TABLE

 "managers" ("manager_name" varchar NOT NULL, "hashed_password" varchar NOT NULL)

プログラムコード等

Controller


class SessionsController < ApplicationController
  def create
    ss_manager = Manager.authenticate(params[:manager_name], params[:password])
    if ss_manager
      session[:manager_id] = ss_manager.id
    else
      flash.alert = "名前とパスワードが一致しません。"
    end
    redirect_to :root
  end

  def destroy
    session.delete(:manager_id)
    redirect_to :root
  end
end

createメソッドでは、画面で入力した名前とパスワードをauthenticateメソッドに渡して、名前とパスワードの一致確認を行います。authenticateメソッドは、後記にも記載しますが、Modelのクラスメソッドです。パスワードの一致確認ができたら、セッションIDを取得します。
destroyメソッドでは、createメソッドで取得したセッションIDを削除しています。

class ApplicationController < ActionController::Base
  private
  def current_manager
    Manager.find_by(id: session[:manager_id]) if session[:manager_id]
  end
  helper_method :current_manager
end

異なるController間で共通に使用するメソッドは、ApplicationControllerに定義します。
ここでは画面参照時にセッションIDの保有有無を判定するcurrent_managerメソッドを実装しています。画面参照時なので、HelperのようにViewで使いたい&DBへアクセスしたいという要件があるので、ControllerにあるメソッドをHelperのようにViewで使う事ができるhelper_methodを定義します。

Model


  class << self
    def authenticate(name, password)
      manager = find_by(manager_name: name)
      if manager && manager.hashed_password.present? &&
          BCrypt::Password.new(manager.hashed_password) == password
        manager
      else
        nil
      end
    end
  end

Modelのクラスメソッドauthenticateです。セッションは、仕組み上Modelを持ちません。
そのため、セッションからDBや外部サービスへアクセスする場合は、Model内にクラスメソッドを定義して、セッション内で使えるようにする必要があります。ここでは名前をキーにDBからパスワードを取得し、そのパスワードをBCryptで復号化して画面で入力したパスワードと一致確認をしています。

ERB


<% if flash.alert %>
  <p class="alert"><%= flash.alert %></p>
<% end %>

<%= form_tag :session do %>
  <table id="login_form">
    <tr>
      <td style="text-align: right">ユーザー名</td>
      <td><%= text_field_tag "manager_name", "", style: "width: 120px" %></td>
    </tr>
    <tr>
      <td style="text-align: right">パスワード</td>
      <td><%= password_field_tag "password", "", style: "width: 120px" %></td>
    </tr>
    <tr>
      <td colspan="2" style="text-align: center">
        <%= submit_tag "ログイン" %></td>
    </tr>
  </table>
<% end %>

<% if current_manager %>
  <p class="manager">
  <%= current_manager.manager_name %>さん|
  <%= link_to "ログアウト", :session,
    method: :delete, data: { confirm: "ログアウトしますか?" } %>
  </p>
<% end %>

form_tag :sessionを定義する事で、submit時にsessions#create(POST)メソッドを呼び出す事ができます。Controllerで定義したhelper_methodのcurrent_managerがここで使われています。セッションIDを保持している場合のみログアウトのリンクが出てくる様になっています。

学んだ事

Webアプリケーションで頻繁に使われるログイン・ログアウトの基本的な実装を学ぶ事ができました。helper_methodの定義方法についても勉強になりました。
次回は、このセッションIDを使ってどんな事ができるのか勉強していきたいと思います。