セキュアなパスワードを実装する
ユーザ認証について
ユーザ認証は以下の手順で行われます。- パスワードの送信。
- ハッシュ化(ハッシュ関数を使って入力されたデータを不可逆なデータにする。)
- データベース内のハッシュ化された値との比較
今回は特にパスワードのハッシュ化の実装について学んだことを残しておこうと思います。
has_secure_password
ハッシュ化されたパスワードを実装する時は、has_secure_passwordメソッドを使います。このメソッドを使用すると以下のことができるようになります。
- ハッシュ化したパスワードを、データベース内のpassword_digestという属性に保存できるようになる。
- authenticateメソッドが使えるようになる。(引数に正しいパスワードを入力すると、正しいユーザ情報を返し、間違ったパスワードだとfalseを返すメソッド)
使用条件
・モデル内にpassword_digestという属性が含まれている。
というわけで、has_secure_passwordを使用するためにpassword_digestという属性をusersテーブルに追加していこうと思います。
password_digestカラム用の適切なマイグレーションを作る。
まずは、ハッシュ化したパスワードを保存するpassword_digestカラムのマイグレーションを生成します。rails generate migration add_password_digest_to_users password_digest:string
こちらのコードで以下のファイルとマイグレーションが生成されます。
class AddPasswordDigestToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :password_digest, :string
end
end
to_usersを末尾につけることで,add_column以下のコードが自動生成されています。
to_カラム名を末尾につけると指定したテーブルに引数で渡したカラムを追加するコードを自動生成してくれます。
ここでデータベースにマイグレーションを実行しましょう。
rails db:migrate
実際にカラムが追加されているかDB Browser for SQliteで確認してみましょう。
無事追加されていることができました。
ここまでで、password_digestカラムを生成することがでいきました。
has_secure_passwordを使うために
password_digestカラムを作成する以外にもやることはあります。has_secure_passwordを使用するためにはハッシュ関数が必要です。なのでハッシュ関数であるbcryptをインストールします。Gemfileにbcryptを追加します。
gem `bcrypt` `3.1.13`
bundle install
これでハッシュ関数が使えるようになりました。
次に、いよいよhas_secure_passwordを使用していきます。
has_secure_passwordを使ってみる
has_secure_passwordはUserモデルに記述します。class User < ApplicationRecord
before_save {self.email = email.downcase}
validates :name, presence: true, length: {maximum: 50}
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: {maximum: 255},
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: true }
has_secure_password #こちらを追加
end
has_secure_passwordの上のコードについてはこちらを参照ください。
これでhas_secure_passwordは実装されました。しかし、このままだとバリデーションとして不完全です。
has_secure_passwordメソッドでは仮想的なpassword属性とpassword_confirmation属性に対してバリデーションする機能が強制的についています。そのためそれらについてのバリデーションを追加する必要があります。
パスワードの最小文字数を設定する
ここでは、password属性とpassword_confirmation属性のバリデーションを作成していきます。今回はの2点についてバリデーションします。
- パスワードが空でないこと。
- 最小文字数が6文字であること。
以下のコードをUserモデルに追加します。
validates :password, presence: true, length: { minimum:6 }
presence:は空でないことについて定義します。length:は長さです。minimum:オプションで最小の長さについて定義しています。
ユーザの作成と認証
では、最後にユーザの作成と認証を実際に行ってみます。今回はrailsコンソールを使用します。
user = User.create(name: "Katsuki Sanada", email: "sana@icloud.com",
password: "111111", password_confirmation: "111111")
=> #<User id: 1, name: "Katsuki Sanada", email: "sana@icloud.com",
created_at: "2022-12-28 01:36:13", updated_at: "2022-12-28 01:36:13",
password_digest: [FILTERED]>
これで、ユーザを作成することができました。
認証にはauthenticateメソットを使います。
user.authenticate("111111")
=> #<User id: 1, name: "Katsuki Sanada", email: "sana@icloud.com",
created_at: "2022-12-28 01:36:13", updated_at: "2022-12-28 01:36:13",
password_digest: [FILTERED]>
正しいパスワードを入力すると、しっかり登録したユーザを返してくれます。
間違ったパスワードを入れたらどうでしょうか?
user.authenticate("333333")
=>false
こちらはfalseを返してくれているので、認証は成功していると言えそうです。
まとめ
- 安全なパスワード認証のためにはhas_secure_passwordを使う。
- ポイントはハッシュ化。
今回の学習はとても刺激的だなぁと思いました。次の内容が楽しみです。