(3)までで永続的なセッション機能の実装まで完了、あとはログアウト機能の実装です。
ログアウト機能(永続的セッションの削除)
- データベースに保存されたトークンをなくす
- クッキーに保存された暗号化された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
コメント