Rails 6.0でアプリを開発 基本の流れ⑧ 永続的ログイン機能
今回はremember_me付きのログイン機能を実装するメモ。
実現したいこと
永続的Cookiesの作成と安全性の高い記憶トークンの生成とトークン認証への活用
Cookiesを読みだす方法と対処法
①パケットスニッファで直接Cookiesを取り出す
対処法:SSLの適用
②DBから記憶トークンを取り出す
③クロスサイトスクリプティングを使う
対処法:Railsが対処
④ユーザーがログインしているデバイスを直接操作
対処法:ユーザーがログアウトするとトークンを必ず変更しデジタル署名も使用
記憶トークンのハッシュ値を保存
・記憶トークンにはランダムな文字列を使用
・トークンをCookiesに保存する際に有効期限を与える
・Cookiesに保存するユーザーIDは暗号化
・IDでDBを検索し、記憶トークンのCookiesがDB内のハッシュ値と一致することを確認
1)remember_digest属性をUserモデルに追加
$ rails g migration add_remember_digest_to_users remember_digest:string
$ rails db:migrate
2)ユーザーを記憶
記憶トークンを作成し、そのトークンをダイジェストに変換したものをDBに保存
下記①~③のメソッドの作成
①new_tokenメソッド
ランダムなトークン生成用メソッド
※ユーザーオブジェクトが不要になるのでUserモデルのクラスメソッドとして作成
②rememberメソッド
トークンの代わりに記憶ダイジェストをDBに保存するメソッド
・記憶トークンをユーザーと関連付けトークンに対応する記憶ダイジェストをDBに保存
・バリデーションを素通りさせるためにupdate_attributeを使用して更新
※2行目attr_accessor:ユーザーモデルにトークンをDBに保存せずに実装するための仮想の属性を作成するもの
③authenticated?メソッド
渡されたトークンがダイジェストと一致したらtrueを返すメソッド
3)次にsessionヘルパー内にも下記メソッドの作成と修正を行う
①rememberメソッド
②createアクション内で呼び出す
③current_userメソッドの修正
4)ユーザーがログアウトできるように再度設定しなおす
①記憶ダイジェストをnilで更新するforgetメソッドの作成
②sessionヘルパーでもforgetヘルパーメソッドとlog_outメソッドを作成
5)rememberダイジェストが存在しないときはfalseを返す処理を実装
ブラウザで2つのウィンドウでログインし片方でログアウトしてしまったときの処理
①テストでチェック(ログアウトをもう一つ追加する)
②sessionsControllerのdestroyアクション内にログインしていたらログアウトするという記述を追加
6)rememberダイジェストがnilの場合falseを返すようにする
2つの別のブラウザでログインした場合にエラーを起こさないように実装
①テストでチェック
②authenticated?メソッドを修正
7)Remember_meチェックボックスでログインを保持する
①ログインフォームにチェックボックスを追加
※ラベルの内側に配置する
②CSSの編集
8)チェックボックスで記憶するかしないかを判断させる
ON → ユーザーを記憶
OFF → 記憶しない
9)テスト内でユーザーがログインするためのヘルパーメソッドを作成
test_helperに2つのlog_in_asメソッドを作成
①テストユーザーとしてログインする
②ActionDispatch::IntegrationTest統合テスト用のテストユーザーとしてログインする
10)チェックボックスがオン、オフ両方の場合のテスト
11)テストから仮想の属性(remember_token)にアクセスする方法
createアクション内のuserをインスタンス変数に変更(user → @user)
アクセスしたいインスタンス変数に対するシンボルをassignの引数で渡す
12)sessions_helper_test.rbを作成し永続的セッションをテスト
$ touch test/helpers/sessions_helper_test.rb
13)今回はやたらめったらエラーが出まくりました。
エラーの内容は
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked
ググるとたくさん出てくるのでよく起きる事象のようですが、サイトで紹介していただいているようにしてもなかなか解除できない。そのくせ、しばらく時間たつと治ってたりもします。
原因は複数のtransactionが発生してロックがかかるみたい。この部分もう少し理解せねばほんとの解決にならないかなっと思っています('_')
参考にさせていただいたサイト
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked - rochefort's blog