Rails

セッションの仕組みを利用して、deviseを使わずにログイン機能を実装してみた

3+
 railsの便利なgemの1つであるdevise
「ログイン機能=devise」みたいになっていたので、deviseを使わずにログイン機能の実装ってどうするんだろう?と思い、調べて実装してみました!

実装イメージ図

手順①サインアップ機能を実装する

BCryptのgemをインストール

BCryptとは、パスワードをハッシュ化するための関数を提供するgemで、Railsアプリケーションを作成した時にGemfileにコメントアウトされた状態で記述されている。このコメントアウトを外してインストールすることで、2つのメソッドを使うことができるようになる

①has_secure_passwordメソッド
・セキュアにハッシュ化した不可逆なパスワードを、データベース内のpassword_digestの属性に保存できるようになる。
passwordとpassword_confirmationを使えるようになる。(これらはDBではなく、メモリに保存される)
※注意※
userモデル内にpassword_digest属性(カラム)を追加していること

②authenticateメソッド
・引数の文字列がパスワードと一致するとそれに紐づくUserオブジェクトを、一致しなければfalseを返すメソッド。

Userモデルとテーブルを作成

Emailのバリデーションについて

メールアドレスはgmailやyahooでは大文字でも登録できるが、携帯キャリアでは登録できない。これはメールサーバーに依存する問題。gmailやyahooだと小文字のアドレスを大文字に変換してもメールを送れるし、受信できるので基本的には大文字・小文字を区別していない仕様になっている。大文字・小文字を区別していない仕様なのであれば、一般的な小文字にフォーマットを統一してDBに保存した方が綺麗だと思ったので、今回のような仕様にしています。

コラム:なぜパスワードを平文でDBに保存してはいけないのか?

なぜ、has_secure_passwordメソッドを使って、セキュアにハッシュ化した不可逆なパスワードを、データベース内のpassword_digestの属性に保存させる必要があるのか?
逆に言うと、なぜパスワードを平文でDBに保存していけないのか?
理由は大きく2点

①会社内部とはいえ、平文だとユーザーのパスワードを簡単に社内の人間が見ることができるので、ヒューマンエラーによって情報漏洩する可能性がある(同じ問題かどうかは別として、ベネッセの個人情報漏洩は似てるかも)

②外部からの不正アクセスにより、万が一情報漏洩があった際に、ユーザー名とパスワードが一緒に漏洩することで二次被害も招くリスクが高くから
②の二次被害で起こると考えられる被害は2つ

①漏洩したユーザー名とパスワードを使って、そのWebサービスに不正ログインされることによる二次被害。例えば、Dropboxのようなサービスだったら、そこに保存してあるデータが全て第三者の手に渡ってしまう恐れがある。

②漏洩したユーザー名とパスワードを使って、別のWebサービスに不正ログインされることによる二次被害。利用者が複数のWebサービスで同じパスワードを使い回していることはよくあることあので、別のWebサービスの情報漏洩等、さらに被害が大きくなる可能性がある。
https://www.atmarkit.co.jp/ait/articles/1902/08/news022.html
パスワードを平文で保存してしまったがために、大きな二次被害を生んでしまうリスクを孕む事件として話題になったのが、「宅ふぁいる便」への不正アクセスによる480万件のユーザー情報流出事件がある。https://www.deep-rain.com/web/security-web/103

手順②Usersコントローラーの作成

最低限必要になるのは、Userの作成(登録)とsignupの画面だけなので、「new」「create」だけ作っておく。追加したければ後で追加すれば良い。

手順③ユーザー登録フォーム(signup)の作成

これで簡単なユーザー登録機能が完成!!
ここからいよいよ、ログイン機能の実装です!!

手順④sessionsコントローラーの作成(コントローラー名は何でもOK)

アクションはnew/create/destroyの3つだけ作成
■new:ログインページ(フォーム)を表示
■create:ログインを完了
■destroy:セッションを破棄(ログアウト)
⇒viewが必要なのはnewだけ

手順⑤ルーティングを編集

手順⑥ログインフォームの作成

※セッションのフォームはユーザーの登録フォームと違って、modelがない。つまり、@userのようなインスタンス変数に相当するものがないので、リソースの名前とそれに対応するURLを具体的に指定する必要がある。

手順⑦sessionsコントローラーにユーザーの検証・認証機能を記述

手順⑧ログイン・ログアウトメソッドを作成

ここでは、Railsのsessionメソッドを使って、Webブラウザへのレスポンスに含まれるset-cookieに、sessions.controller.rbのcreateアクションで認証したユーザーのuser.idを暗号化したものをセッション情報を持たせるという実装をしていきます。

■log_inメソッド

これで、ユーザーのブラウザ内の一時cookiesに暗号化済のユーザーIDが自動生成される。これらは使い回しができるように、helperメソッドとして作っておく。

合わせて、現在ログインしているユーザーオブジェクトを返すメソッドと、ユーザーがログインしているかどうかを評価するメソッドも作っておく。

このSessionsHelperモジュールのメソッドをコントローラーで使えるようにapplication_controller.rbにincludeしておく

これで、下記のような記述ができる。

■log_outメソッド
⇒セッションIDを削除して、現在のユーザーをnilに設定する

あとは、sessionsコントローラーにこれらを記述すれば完成!!

 

今回はあくまで、ログインに必要最低限の部分しか実装していませんが、これらを簡単に使えるようにしているdeviseはつくづく便利なgemだなと思いました笑

3+