rails 独学して軽くにちゃんまとめつくる

永久セッションをつかうログイン機能

f:id:mooooooooooriiiiii:20161218085237p:plain

 

  1. 記憶トークンにはランダムな文字列を生成して用いる。
  2. トークンはハッシュ値に変換してからデータベースに保存する。

  3. ブラウザのcookiesにトークンを保存するときには、有効期限を設定する。
  4. ブラウザのcookiesに保存するユーザーIDは暗号化しておく。

  5. 永続ユーザーIDを含むcookiesを受け取ったら、そのIDでデータベースを検索し、記憶トークンのcookiesがデータベース内のハッシュ値と一致することを確認する。

$ rails generate migration add_remember_digest_to_users remember_digest:string

 

rails db:migrate

 

 

①&②サーバー編

rememberメソッドが主。記憶トークンにランダムな文字列を記憶させ、それをさらにハッシュ化してたあたいをデータベースにremember_digest として保存している。この時点ではサーバー側で保存しているメソッドを定義しているだけ。保存する作業はセッションヘルパーで。

class User < ApplicationRecord
  attr_accessor :remember_token

 # 渡された文字列のハッシュ値を返す
  def User.digest(string)
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                  BCrypt::Engine.cost
    BCrypt::Password.create(string, cost: cost)
  end
 
  # ランダムなトークンを返す
  def User.new_token
    SecureRandom.urlsafe_base64
  end


  #永久セッションのためにユーザをデータベースに保存する
  def remember
    self.remember_token = User.new_token
    update_attribute(:remember_digest, User.digest(remember_token))
  end
end

 

 

 

3&4 クライアント編

クライアント側に保存するクッキーは user_id と記憶トークンの2つ。パスワードと似たものを感じる。

 

app/controllers/sessions_controller.rb

def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      log_in user
remember user redirect_to user else

 

app/helpers/sessions_helper.rb

def remember(user)
    user.remember
    cookies.permanent.signed[:user_id] = user.id
    cookies.permanent[:remember_token] = user.remember_token
  end

 

 

 

5 認証編

 

def authenticated?(remember_token)
return false if remember_digest.nil? BCrypt::Password.new(remember_digest).is_password?(remember_token)
end

 

 

 

6ログアウト

簡易版のログイン機能でもつけたがさらに拡張する。

ログアウトとは、データベースからremember_digestを消し、cookiesを消し、セッションを消し、@current_userをnil にすることである。言い換えればログインするときに作ったデータを消す作業。

 

データベースからの削除

app/models/user.rb

def forget
   update_attribute(:remember_digest, nil)
end

 

 クッキーの削除

app/hepers/sessions_helper.html.erb

def forget(user)
  user.forget
  cookies.delete(:user_id)
  cookies.delete(:remember_token)
end

 

セッションの削除とほかのやつの統合

app/hepers/sessions_helper.html.erb

def log_out
    forget(current_user)
    session.delete(:user_id)
    @current_user = nil
  end

 

コントローラー

  def destroy
    log_out if loged_in?
    redirect_to root_url
  end

 

remember_me チェックボックスで制御

ビュー

チェックボックスをいれるだけ

sessions/new.html.erb

<%= f.label :remember_me, class: "checkbox inline" do %>
   <%= f.check_box :remember_me %>
   <span>パスワードを記憶する</span>

<% end %>

 

セッションコントローラー

def create

.

.

params[:session][:remember_me] == '1' ? remember(user) : forget(user)

 

 

 

あとの微調整

 

セッションヘルパーで定義した current_user が永久セッションに対応してないので、書き換える

 

def current_user
  if user_id = session[:user_id]
    @current_user ||= User.find_by(id: user_id)
  elsif user_id = cookies.signed[:user_id]
    user = User.find_by(id: user_id)
    if user && user.authenticated?(cookies[:remember_token])
      @current_user = user
    end
  end
end