Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

Ruby on Rails | ユーザー認証時にBCryptによる暗号化を行う

概要

ユーザー認証時にBCrypによる暗号化を行う

内容

サンプル

要件

・ユーザー作成画面から新規ユーザーのパスワードを暗号化登録
・サインイン画面からDBの暗号化されたパスワードで認証を行う

Gemfileで'bcrypt-ruby'を指定します
'bcrypt-ruby', '~>3.0.0

そしてbundleを実行します

bundle
Userモデルを生成します。
besrl g model user name:string login:string email:string password_digest:string
      invoke  active_record
      create    db/migrate/20130713073057_create_users.rb
      create    app/models/user.rb
      invoke    rspec
      create      spec/models/user_spec.rb
マイグレーションを実行します
besrk db:migrate
==  CreateUsers: migrating ====================================================
-- create_table(:users)
   -> 0.0308s
==  CreateUsers: migrated (0.0310s) ===========================================
作成されたテーブルを確認します
mysql> desc users;
+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| id              | int(11)      | NO   | PRI | NULL    | auto_increment |
| name            | varchar(255) | YES  |     | NULL    |                |
| login           | varchar(255) | YES  |     | NULL    |                |
| email           | varchar(255) | YES  |     | NULL    |                |
| password_digest | varchar(255) | YES  |     | NULL    |                |
| created_at      | datetime     | YES  |     | NULL    |                |
| updated_at      | datetime     | YES  |     | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+
Userコントロールを作成します

新規登録画面用のnewと登録実行用のcreateアクションを定義します。

bes rails g controller user new create
      create  app/controllers/user_controller.rb
       route  get "user/create"
       route  get "user/new"
      invoke  haml
      create    app/views/user
      create    app/views/user/new.html.haml
      create    app/views/user/create.html.haml
      invoke  rspec
      create    spec/controllers/user_controller_spec.rb
      create    spec/views/user
      create    spec/views/user/new.html.haml_spec.rb
      create    spec/views/user/create.html.haml_spec.rb
      invoke  helper
      create    app/helpers/user_helper.rb
      invoke    rspec
      create      spec/helpers/user_helper_spec.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/user.js.coffee
      invoke    scss
      create      app/assets/stylesheets/user.css.scss
新規ユーザー登録画面を作成します

models

class User < ActiveRecord::Base
  has_secure_password
  validates :name, presence: true, :uniqueness => true
  validates :login, presence: true, :uniqueness => true
  validates :email, presence: true, :uniqueness => true
end

ApplicationController
|

ApplicationControllerにカレントユーザー取得を追加、各処理でログインチェックをするための処理を追加
class ApplicationController < ActionController::Base
  # :
  before_filter :authorize

  def authorize
    return redirect_to :controller => 'signin', :action => 'index' unless session[:user_id]
  end

  private
     
  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end
  
  helper_method :current_user
end

controller

class UserController < ApplicationController
  def new
    @messages = flash[:messages]
    @user = params[:user] || User.new
  end

  def create
    user = User.create do |b|
      b.name = params[:name]
      b.login = params[:login]
      b.email = params[:email]
      b.password = params[:password]
      b.password_confirmation = params[:password_confirmation]
    end
    if user.errors.any?
      flash[:messages] = user.errors.full_messages
      return redirect_to :action=>'new'
    end
    redirect_to :action=>'list'
  end

  def list
    @users = User.all
  end
end

view 一覧

%h1 User#list
%p Find me in app/views/User/list.html.haml
%hr/ 
= link_to '新規登録', :controller => 'user', :action => 'new'
%hr/ 
%table 
  %tr 
    %th id
    %th name
    %th login
    %th email
    %th created_at
    %th updated_at
  -@users.each do |u|
    %tr 
      = content_tag :td, u.id
      = content_tag :td, u.name
      = content_tag :td, u.login
      = content_tag :td, u.email
      = content_tag :td, show_dat(u.created_at)
      = content_tag :td, show_at(u.updated_at)

view 新規作成

%h1 User#new
%p Find me in app/views/user/new.html.haml
%hr/ 
= link_to '戻る', :controller => 'user', :action => 'list'
%hr/ 
- unless @messages.blank?
  %div
    - @messages.each do |m|
      %p 
        =m
    %hr/ 
=form_tag("/user/create") do
  %p 
    =label_tag 'name', 'name'
    =text_field_tag 'name'
  %p 
    =label_tag 'login', 'login'
    =text_field_tag 'login'
  %p 
    =label_tag 'email', 'email'
    =text_field_tag 'email'
  %p 
    =label_tag 'password', 'Password'
    =password_field_tag 'password'
  %p 
    =label_tag 'password_confirmation', 'Password Confirmation'
    =password_field_tag 'password_confirmation'
  %p 
    =submit_tag 'submit'
サインイン画面とログイン認証を作成します。

controller

class SigninController < ApplicationController
  skip_filter :authorize, :except=>:index

  def index
    flash[:message]
  end

  def signin
    user = User.find_by name: params[:login]
    unless user && user.authenticate(params[:password])
      flash[:message] = "fail password authentication"
      return redirect_to action: 'index'
    end

    session[:user_id] = user.id
    redirect_to controller: 'user',action: 'list'
  end

  def signout
    session[:user_id] = nil
    flash[:message] = "ログアウトしました"
    redirect_to :controller => 'signin', :action => 'index'
  end
end

view

%h1 BookShelfSystem
%hr/ 
- unless flash[:message].blank?
  %div
    %p 
      =flash[:message]
    %hr/ 
=form_tag("/signin/signin") do
  %p 
    =label_tag 'login', 'login'
    =text_field_tag 'login'
  %p 
    =label_tag 'password', 'Password'
    =password_field_tag 'password'
  %p 
    =submit_tag 'submit'

操作

ユーザー一覧

新規ユーザー登録

登録時パスワード、確認用パスワード比較失敗

登録成功

成功時DB

暗号化されていることが確認出来る

mysql> select * from users;
+----+-----------+------------+---------------+--------------------------------------------------------------+---------------------+---------------------+
| id | name      | login      | email         | password_digest                                              | created_at          | updated_at          |
+----+-----------+------------+---------------+--------------------------------------------------------------+---------------------+---------------------+
|  1 | a         | a          | a             | $2a$10$Z90ZZWkToKNapWyf8A5BPO..TvIQ0WT9t7HmKWhCInTZn0wDaM8N6 | 2013-07-13 09:17:42 | 2013-07-13 09:17:42 |
|  2 | b         | b          | b             | $2a$10$kO/DrCJQqhrSdnKKWay4OehKXBHwrS8RRLOzJfSqfJXTRby8SVW4e | 2013-07-13 10:50:52 | 2013-07-13 10:50:52 |
|  3 | hoge_name | hoge_login | hoge@hoge.com | $2a$10$Dps8c7Cbxtu9Spq.3S4rmeVoqR9Opo.q7AkPHg5IZqDrPbho4Vt9S | 2013-07-13 11:15:42 | 2013-07-13 11:15:42 |
+----+-----------+------------+---------------+--------------------------------------------------------------+---------------------+---------------------+
サインインページ 新規追加したユーザーでログイン失敗

サインインページ 新規追加したユーザーでログイン成功 => ユーザー一覧画面へ遷移