0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rails Tutorial(2週目)-9-

Posted at

記憶トークンの作成

Ruby標準ライブラリのSecureRandomモジュールにあるurlsafe_base64メソッド(A–Z、a–z、0–9、"-"、"_"のいずれかの文字 (64種類) からなる長さ22のランダムな文字列を返す)を使用して、記憶トークンを作成する

具体的には、

app/models/user.rb
class User < ApplicationRecord
  attr_accessor :remember_token 

# (省略)

# ランダムなトークンを返す
  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

としておく。

クラスメソッドのnew_tokenでは記憶トークンを作成。rememberメソッドでは、現在のユーザーのremember_token属性をnew_tokenメソッドを用いて作成する。その後、update_attributeの第一引数に変更を加える属性(:remember_digest)を指定し、第二引数にremember_tokenをdigestメソッドを用いて暗号化したものをセッティングして、値の更新を行っている。

つまり、rememberメソッドでは、記憶トークンを現在のユーザーと紐づけ、その記憶トークンを暗号化して、DBにremember_digest属性として保存している。

cookiesに保存

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

上のrememberメソッドでは、user.rememberで先程のrememberクラスメソッドを引数で与えられたユーザーに対して実行。
cookies.permanent.signed[:user_id] = user.id
では、permanent(期限の設定)とsigned(署名付きにする)をメソッドチェーンしてcookiesに対して行う。またcookiesはsessionと同様にハッシュのように取り扱うことができる。
記憶トークンの方も同様にcookiesに保存している。

記憶トークンの認証

app/models/user.rb
 # 渡されたトークンがダイジェストと一致したらtrueを返す
  def authenticated?(remember_token)
    BCrypt::Password.new(remember_digest).is_password?(remember_token)
  end

上のコードで、暗号化されたremember_digestと、引数として与えられた値を暗号化したものが同じになるか比較して認証。

current_userメソッドをcookiesに対応させる

app/helpers/sessions_helper.rb
# 記憶トークンcookieに対応するユーザーを返す
  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])
        log_in user
        @current_user = user
      end
    end
  end

if (user_id = session[:user_id])の部分では、変数user_idにsession[:user_id]の値を代入した結果、session[:user_id]が存在すれば、という意味。

永続的セッションの削除

app/models/user.rb
  # ユーザーのログイン情報を破棄する
  def forget
    update_attribute(:remember_digest, nil)
  end

ユーザーモデルにforgetメソッドを定義して、remember_digest属性をnilにする

app/helpers/sessions_helper.rb
# 永続的セッションを破棄する
  def forget(user)
    user.forget
    cookies.delete(:user_id)
    cookies.delete(:remember_token)
  end

  # 現在のユーザーをログアウトする
  def log_out
    forget(current_user)
    session.delete(:user_id)
    @current_user = nil
  end

forgetで永続的セッションの削除。log_outで永続的セッションの削除と、セッションの削除を行う。

チェックボックスの作成

app/views/sessions/new.html.erb
 <%= f.label :remember_me, class: "checkbox inline" do %>
        <%= f.check_box :remember_me %>
        <span>Remember me on this computer</span>
 <% end %>

ここで与えられたデータは、params[:session][:remember_me]で取り出せる。

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
      params[:session][:remember_me] == '1' ? remember(user) : forget(user)
      redirect_to user
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

params[:session][:remember_me] == '1' ? remember(user) : forget(user)は三項演算子を使っている。
論理値? ? 何かをする : 別のことをする
上のコードでは、params[:session][:remember_me]の値が1なら、remember(user)を実行し、それ以外なら、forget(user)を実行するということ。

ログイン時にforget(user)を実行して大丈夫なのだろうかと思ったけれど、cookies関連の情報がnilになるだけなので、ログインはできる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?