#AWSへデプロイ後に、bcryptで暗号化したパスワードでログインできない現象についての対処法
プログラミング初学者です。Ruby on Railsで作成したアプリをAWSのEC2インスタンスにデプロイした後で、作成したアカウントにログインできない現象が発生しました。パスワード周りのエラーの解消に丸一日かかってしまいましたので、また同じ現象で困らないためにもこの記事にまとめておきたいと思います。
##発生した環境
Rubyバージョン:2.5.8
Railsバージョン:6.1.1
gem bcryptバージョン:3.1.16
##発生した現象
デプロイ後に新規登録したアカウントに、始めはログインできていたのですが、しばらく経ってからログインしようとすると「メールアドレスかパスワードに誤りがあります」と表示されログインできなくなりました。
##試したこと
###ログを確認
$ vim log/production.log
いくつかのエラーログを確認しましたので、順に確認していきました。
###Mysql2::Error
ActiveRecord::StatementInvalid (Mysql2::Error: Unknown column 'password_digest' in 'field list'):
bcryptでパスワードの暗号化を行なった際に、'password_digest'カラムをデータベースのusersテーブルに追加していました。mysqlにログインしたところ、確かに'password_digest'カラムは存在して値が保存されていました。
###ArgumentError
ArgumentError (wrong number of arguments (given 0, expected 1)):
app/controllers/users_controller.rb:41:in `login'
値が入るはずの場所に値が入っていないことが確認できました。
該当の場所には下記コードがありました。
if @user && @user.authenticate(params[:password])
どうやら入力したパスワードが正常に認識されていないことがわかりました。
###NoMethodError
NoMethodError (undefined method `encrypted_password=' for #User:0x000000000572e6d8):
'encrypted_password'は何のことかとわからなかったので、検索するとDeviseを導入した時に追加されるという情報がありました。確認すると、確かにGemfileに「gem 'devise'」を追加していました。そこで、encrypted_passwordを利用したパスワードの暗号化に切り替えることにしました。
##password_digestからencrypted_passwordへの切り替え
まずmysqlでusersテーブルのカラム名を変更します。
mysql> alter table users change column password_digest encrypted_password char(255);
user.rbを編集します。
class User < ApplicationRecord
has_secure_password #ここを削除します
validates :name, {presence: true}
validates :email, {presence: true, uniqueness: true}
validates :image_name, {presence: true}
validates :password, {presence: true} #ここも不要になるので削除します
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :omniauthable
end
users_controller.rbを編集します。
エラーが発生していた、ログイン認証の行の認証メソッドを書き換えます。
if @user && @user.valid_password?(params[:password]
パスワードを変更する部分が少々手こずりました。
params[:password]に保存されている新しいパスワードを手動で暗号化して更新しています。
if params[:password]
hashed_password = BCrypt::Password.create(params[:password])
update_password_sql = "update users set encrypted_password = '#{hashed_password}' where id =#{@current_user.id};"
ActiveRecord::Base.connection.execute(update_password_sql)
end
コードの編集が終わったらサーバーを再起動します。
nginxを再起動します。
$ sudo service nginx restart
続いてunicornを再起動します。unicornで走っているスレッドを確認します。
$ ps -ef | grep unicorn | grep -v grep
3行の走っているスレッド番号が表示されます。
下は一行目の一例です。
ユーザー名 番号 1 0 11:16 ? 00:00:00 unicorn_rails master -c /var/www/アプリのディレクトリ/config/unicorn.conf.rb -D -E production
…
スレッドを停止します。
$ kill 番号
もう一度上記の確認コマンドを打ち込んで何も表示されなければ、スレッドが終了しています。
unicornを起動します。
$ bundle exec unicorn_rails -c /var/www/アプリのディレクトリ/config/unicorn.conf.rb -D -E production
確認コマンドを打ち込んでスレッド番号が表示されれば、再起動できています。
##まとめ
丸一日かかってしまったので、思い出せる限り全部の工程をまとめました。
某プログラミング学習サイトでパスワードの暗号化を習い、簡単にできるものだと思っていたら思わぬ落とし穴がありました。Twitter連携などに使用するDeviseを導入することで、パスワード暗号化の機能が重複してエラーを発生するようです。簡単に習っただけでは実践には足りない、実際にエラーに遭遇することで腕を磨くものだと、今後の良い戒めになりました。