sorceryでパスワードリセット機能を実装する
こんにちは。しおはまです。
今回はsorceryというGemを使ってパスワードをリセットする機能を実装する過程をまとめてみたいと思います。
sorceryとは
そもそもsorceryってどういうGemなのか説明します。
Sorceryは、ユーザ認証機能を簡単に実装できるライブラリで、MITライセンスのオープンソースソフトウェアとして公開されています。
↑がsorceryのgithubです。
ユーザの認証の基本的な機能であるパスワード認証を始め、
- User Activation
- Reset Password
- Remember Me
- Session Timeout
- Brute Force Protection
- Basic HTTP Authentication
- Activity Logging
といった機能が揃っており、必要に応じて機能を選んで使うことができます。
ログイン機能やパスワード認証の実装についても今後ブログでまとめたいですが、今回はパスワードをリセットする方法にフォーカスを当ててまとめていきたいと思います。
なお、ログイン機能については今回は実装できている前提で説明をしますのでご了承ください。
sorceryのインストール
さっそくパスワードをリセットする方法について見ていきます。
まずは、Gemfileにsorceryを記述してbundle installしましょう。
# Gemfile gem 'sorcery'
パスワードのリセットを実装するにはsorceryのReset Passwordというmoduleを使用します。
こちらのgithubに一連の流れは書いてあるので、より正しい情報が知りたいという方は参照してみてください。
moduleのインストールとマイグレーションファイルの作成
まず初めの手段として下記のコマンドでmoduleのインストールとマイグレーションファイルの作成をします。
$ rails g sorcery:install reset_password --only-submodules
コマンドを叩くと、自動的にマイグレーションファイルが作成されます。
class SorceryResetPassword < ActiveRecord::Migration def change add_column :users, :reset_password_token, :string, default: nil add_column :users, :reset_password_token_expires_at, :datetime, default: nil add_column :users, :reset_password_email_sent_at, :datetime, default: nil add_index :users, :reset_password_token end end
マイグレーションファイルが作成されたことを確認して、マイグレーションを実行します。
$ rails db:migrate
config/initializers/sorcery.rb(sorceryの設定ファイル)を見ると自動的にpassword_resetのサブモジュールを使用することが書かれています。
# Gemfile Rails.application.config.sorcery.submodules = [:reset_password] #################################### Rails.application.config.sorcery.configure do |config| config.user_config do |user| user.reset_password_mailer = UserMailer end end
PasswordResetsコントローラーの追加
ここまで設定できたらrails gコマンドでPasswordResetsコントローラーを作成します。
アクションはパスワードを変更するcreate、編集ファイルのedit、作成するためのupdateを指定します。
rails g controller PasswordResets create edit update
PasswordResetsコントローラーが作成できたらReset passwordのgithubにしたがってコードを記述します。(多少カスタマイズしているところもありますが、おおまかなところは変わり無いです)
class PasswordResetsController < ApplicationController skip_before_action :require_login def create @user = User.find_by(email: params[:email]) @user&.deliver_reset_password_instructions! if @user flash[:success] = 'パスワードリセット手順を送信しました' redirect_to root_path end def edit @token = params[:id] @user = User.load_from_reset_password_token(params[:id]) return not_authenticated if @user.blank? end def update @token = params[:id] @user = User.load_from_reset_password_token(params[:id]) return not_authenticated if @user.blank? @user.password_confirmation = params[:user][:password_confirmation] if @user.change_password(params[:user][:password]) flash[:success] = 'パスワードを変更しました' redirect_to login_path else flash.now[:danger] = 'パスワードを変更できませんでした' render :edit end end end
細かいメソッドの説明は割愛しますが、createアクションはパスワードをリセットするためのメールアドレスを送信し、どのユーザーのメールアドレスかを判定します。
editアクションでは実際にパスワードをリセットするための判定がされています。(詳しくはgithubのWikiでload_from_reset_password_tokenの動きなどを確認するといいと思います)。
updateアクションではパスワードをリセットする動きを制御しています。
if @user.change_password
の部分でパスワードの条件分岐をしており、正しくパスワードが入力されたらtrueになり、正常にパスワードがリセットされるということになります。
ルーティングの設定
コントローラーまで設定できたら次にルーティングの設定をしていきます。
ルーティングの設定は簡単ですね。
# route.rb resources :password_resets, only: [:create, :edit, :update]
これでルーティングが正しく設定されますね。
送信メールの設定
ルーティングの設定ができたら送信するためのメールを設定していきます。
# reset_password_email.text.erb Hello, <%= @user.email %> =============================================== You have requested to reset your password. To choose a new password, just follow this link: <%= @url %> Have a great day!
ここは自分が送信メールで設定できる部分なので自由にコードを書いてもいいのですが、<%= @user.email %>でパスワードをリセットするために送信したメールアドレス、<%= @url %>にパスワードをリセットするためのURLが記載されますので、ご注意ください。
# app/mailers/user_mailer.rb def reset_password_email(user) @user = User.find user.id @url = edit_password_reset_url(@user.reset_password_token) mail(:to => user.email, :subject => "Your password has been reset") end
user_mailer.rbはApplicationMailerを継承しており、メールに関する設定を変更できます。
特にmail(to: user.email, subject: 'パスワードリセット')で、メールの送信元、メールの題名を設定することができます。
フォームの作成
ここまで設定できたらあとはフォームを作成するだけです。
どのようにフォームを作成するかは個人個人で違うと思いますが、githubを参考に# app/views/password_resets/new.html.erbや# app/views/password_resets/create.html.erbにコードを書いていくと簡単に作成することができます。
まとめ
ここまで読んでいただきありがとうございます。
長くなってしまいましたが、パスワードリセット機能はログイン機能を実装したら必然的にリセット機能も必要になってくるのでしっかり理解しておきたいところですね。
にしてもsorceryは使いたい機能を使う時にサブモジュールをインストールして自分で実装できるのがいいですね。