読者です 読者をやめる 読者になる 読者になる

ぞえの技術めも

Ruby on Rails勉強中

【86日目】【1日20分のRailsチュートリアル】【第8章】ログイン状態の保持機能を追加する

Ruby on Railsチュートリアル(第3版)

今日は「8.4.2 ログイン状態の保持」のトークンが記憶ダイジェストと一致するか確認するから。

8.4.2 ログイン状態の保持

攻撃者が仮に両方のcookiesを奪い取ることに成功したとしても、本物のユーザーがログアウトするとログインできないようになっています。

記憶トークンとユーザーIDのcookiesを奪い取られてもログインできないらしい。

渡されたトークンがユーザーの記憶ダイジェストと一致することを確認します。

secure_passwordのソースコードを参考にして最終的には下記のような形に。

is_password?がどういうメソッドなのかよく分からないなぁ…。

BCrypt::Password.new(remember_digest).is_password?(remember_token)

上記を踏まえUserモデルにトークンをチェックするメソッドを追加。

app/models/user.rb

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

ログインするときの処理にrememberメソッドを追加。

app/controllers/sessions_controller.rb

    :
    if user && user.authenticate(params[:session][:password])
      log_in user
      remember user
      redirect_to user
    else
    :

Sessionヘルパーにrememberメソッドを作成。

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

永続セッションの場合は、session[:user_id]が存在すれば一時セッションからユーザーを取り出し、それ以外の場合はcookies[:user_id]からユーザーを取り出して、対応する永続セッションにログインする必要があります。

状況によって一時セッションとcookiesを使い分けるようにcurrent_userメソッドを修正。

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

ブラウザのcookiesを削除する手段が未実装なので (20年待てば消えますが)、ユーザーがログアウトできません。

ログアウトボタン押してもcookiesが削除されない=ログアウトできないのでテストがNGとなることを確認。

$ bundle exec rake test
24 tests, 59 assertions, 1 failures, 0 errors, 0 skips

実際にcookiesに保存されるかどうかはまだ動作見てない。それは追々。
なんか難しくなってきたなぁ、という印象。。。「記憶トークン」という単語が見慣れないからかも?

今日の作業時間は【32分】

次は「8.4.3 ユーザーを忘れる」から。