ログイン機能(4) Ruby on Rails

(3)までで永続的なセッション機能の実装まで完了、あとはログアウト機能の実装です。

ログアウト機能(永続的セッションの削除)

  1. データベースに保存されたトークンをなくす
  2. クッキーに保存された暗号化されたuser_idとトークンを削除する

1.データベースに保存されたトークンをなくす。

models/user.rb

def forget
update_attribute(:remember_digest, nil)
end

2.クッキーに保存された暗号化されたuser_idとトークンを削除する

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

必然的バグを直す

ユーザーは場合によっては同じサイトを複数のタブで開いていることがある。
ログアウト用のリンクはログイン状態でのみ表示されるが、今のcurrent_userの用途ではユーザーが1つめのタブでログアウトを実行し、さらに2つめのタブでもログアウトを実行するとエラーが発生してしまう。

解決方法:ユーザーがログイン状態の場合のみログアウト処理を実行させる

sessions_controller

def destroy
log_out if logged_in?
flash[:success] = “ログアウトしました。”
redirect_to root_url
end

ユーザーが複数のブラウザ(例えばGoogle ChromeとFirefox)でログインしていたとする。
この時Firefoxでログアウトし、Chromeではログアウトせずにブラウザを終了させ再度Chromeで同じページを開くと問題が発生してしまう。

原因はFirefoxでログアウトしたときにユーザーのremember_digestが削除してしまっているにも関わらず、Chromeでアプリケーションにアクセスしたときに次のコードを実行してしまうからです。

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

解決方法:この問題を回避するためにはremember_digestが存在しない場合はfalseを返して処理を終了するようauthenticated?メソッドを修正する

models/user.rb

def authenticated?(remember_token)
return false if remember_digest.nil? ⇦ これを追加
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end

コメント

タイトルとURLをコピーしました