[Rails]deviseによるユーザー認証 1/2
はじめに
devise
gemを使ってrailsアプリに認証機能を導入していきます。
ドキュメントを参考しながらやっていきます。
環境:
Rails 6.1.7.3
ruby 3.0.0
devise
をインストールする
gem 'devise'
bundle install
devise
を生成する
bin/rails generate devise:install
create config/initializers/devise.rb
create config/locales/devise.en.yml
devise.en.yml
はフラッシュメッセージのファイルとなります。
同じディレクトリ内にdevise.ja.yml
を作成し、日本語のフラッシュメッセージを追加します。
メーラー用URLを追加する
開発環境でメールを確認したい場合はletter_opener_web
というgemと一緒に使うと便利です。
Rails.application.configure.do
# letter_opener
config.action_mailer.delivery_method = :letter_opener_web
config.action_mailer.perform_deliveries = true
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end
メーラー用のurlを追加します。
Rails.application.routes.draw do
mount LetterOpenerWeb::Engine, at: '/letter_opener' if Rails.env.development?
end
Userモデルを作成する
bin/rails generate devise user
invoke active_record
create db/migrate/20230714115356_add_devise_to_users.rb
insert app/models/user.rb
route devise_for :users
コメントアウトされたモジュールを有効化にする場合マイグレーションファイルにコメントアウトされたカラムを解除してからマイグレーションしましょう。
class User < ApplicationRecord
# Include default devise modules. Others available are:
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable, :lockable, :timeoutable, :trackable, :omniauthable
end
各モジュールとそれぞれの機能について:
-
:database_authenticatable
: パスワードベースの認証を提供します。パスワードは暗号化され、データベースに保存されます。 -
:registerable
: ユーザーの新規登録と編集を可能にします。 -
:recoverable
: パスワードリセット機能を提供します。ユーザーはパスワードリセット用のメールを受け取り、リンクをクリックすることで新しいパスワードを設定できます。 -
:rememberable
: ユーザーのログイン状態を記憶し、ブラウザのセッションを保持します。 -
:trackable
: ユーザーのログイン回数、最終ログイン時刻などのトラッキング情報を保存します。 -
:validatable
: ユーザーモデルのバリデーションを提供します。メールアドレスの一意性やパスワードの複雑さなどのバリデーションを簡単に設定できます。 -
:confirmable
: メール確認機能を提供します。ユーザーは登録メールの確認リンクをクリックしてアカウントを有効化する必要があります。 -
:lockable
: ユーザーアカウントのロックアウト機能を提供します。一定回数のログイン試行失敗後にアカウントがロックされます。 -
:timeoutable
: ユーザーセッションのタイムアウト機能を提供します。一定時間アクティビティがない場合にセッションを自動的にログアウトします。 -
:omniauthable
: OmniAuthを使用したソーシャルログイン(Facebook、Twitter、Googleなど)を簡単に実装するための機能を提供します。
bin/rails db:migrate
Running via Spring preloader in process 14619
== 20230714115356 AddDeviseToUsers: migrating =================================
-- change_table(:users)
-> 0.0052s
-- add_index(:users, :email, {:unique=>true})
-> 0.0118s
-- add_index(:users, :reset_password_token, {:unique=>true})
-> 0.0008s
== 20230714115356 AddDeviseToUsers: migrated (0.0180s) ========================
has_secure_password
を削除する
Railsが用意してくれたhas_secure_password
を使ってpassword_digest
でユーザーのパスワードを管理してましたが、devise
では代わりにencrypted_password
があるためhas_secure_password
を削除します。
ヘルパーメソッド
Deviseには、ユーザー認証に関連するさまざまなヘルパーメソッドが用意されています。
メソッド | 使い方 |
---|---|
authenticate_user! | ユーザーが認証されていない場合、このヘルパーメソッドを使用してリクエストを中断し、ログインページにリダイレクトします。アクションの前にフィルターとして使用されることがあります。 |
current_user | 現在ログインしているユーザーのインスタンスを返します。アプリケーションのどこからでもログインしているユーザーの情報にアクセスするために使用できます。 |
user_signed_in? | ユーザーがログインしているかどうかを判定します。ログインしている場合はtrue 、ログアウトしている場合はfalse を返します。 |
user_session | ユーザーのセッション情報を管理するためのヘルパーメソッドです。セッションを明示的に操作する必要がある場合に使用します。 |
authenticate_user!
を使う
Deviseのuser_signed_in?
メソッドを使用してユーザーがログインしているかどうかをチェックします。
ユーザーがログインしていない場合、現在のページを保存し、ユーザーをログインページにリダイレクトします。ユーザーがログインした後に元のリクエストされたURLにリダイレクトされます。
module Devise
module Controllers
module Helpers
def authenticate_user!
unless user_signed_in?
store_location_for(:user, request.url)
redirect_to new_user_session_path
end
end
# ...
end
end
end
Articles
コントローラーにbefore_action
を追加し、特定のアクションやページに対して認証を要求することができます
class ArticlesController < ApplicationController
before_action :authenticate_user!, only: %i[new create edit update destroy]
end
ルーティングを追加する
devise_for
は認証関連のルーティングを作成してくれるメソッドです。
Rails.application.routes.draw do
devise_for :users
end
作成されるルーティングはこちらになります。
ログインする時のURLは/users/sign_in
となっていますが、カスタマイズすることができます。
Rails.application.routes.draw do
devise_for :users, path: 'auth', path_names: { sign_in: 'login', sign_out: 'logout' }
end
新規登録フォーム
http://localhost:3000/users/sign_up
ログインフォーム
http://localhost:3000/users/sign_in
デフォルトで用意されたビューとなります。
新規登録画面とログイン画面を変更したい場合、カスタムビューを作成することができます。
カスタムビューを作成する
gemにあるビューファイルをapp/views/users/devise
ディレクトリ配下に作成されます。
bin/rails generate devise:views
invoke Devise::Generators::SharedViewsGenerator
create app/views/devise/shared
create app/views/devise/shared/_error_messages.html.erb
create app/views/devise/shared/_links.html.erb
invoke form_for
create app/views/devise/confirmations
create app/views/devise/confirmations/new.html.erb
create app/views/devise/passwords
create app/views/devise/passwords/edit.html.erb
create app/views/devise/passwords/new.html.erb
create app/views/devise/registrations
create app/views/devise/registrations/edit.html.erb
create app/views/devise/registrations/new.html.erb
create app/views/devise/sessions
create app/views/devise/sessions/new.html.erb
create app/views/devise/unlocks
create app/views/devise/unlocks/new.html.erb
invoke erb
create app/views/devise/mailer
create app/views/devise/mailer/confirmation_instructions.html.erb
create app/views/devise/mailer/email_changed.html.erb
create app/views/devise/mailer/password_change.html.erb
create app/views/devise/mailer/reset_password_instructions.html.erb
create app/views/devise/mailer/unlock_instructions.html.erb
特定のビューだけをカスタマイズする場合オプションを入れることができます。
rails generate devise:views -v registrations confirmations
新規登録フォームをカスタマイズする
新規登録フォームにユーザー名を追加していきます。
devise
のストロングパラメーターにuser_name
を追加します。
追加する場所はApplication
コントローラーになります。
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:user_name])
end
end
新規登録ビューにbootstrapスタイルを適用する
<h2><%= t('devise.registrations.new.sign_up') %></h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="form-group">
<%= f.label :user_name %><em>(<%= t('devise.shared.minimum_password_length', count: 3 ) %>)</em>
<%= f.text_field :user_name, autofocus: true, class: 'form-control mb-3'%>
</div>
<div class="form-group">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email", placeholder: "user@example.com", class: 'form-control mb-3'%>
</div>
<div class="form-group">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= t('devise.shared.minimum_password_length', count: 6 ) %>)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password", class: 'form-control mb-3'%>
</div>
<div class="form-group">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: 'form-control mb-3'%>
</div>
<%= f.submit class:'btn btn-primary' %>
<% end %>
<%= render "devise/shared/links" %>
ログインビューにbootstrapスタイルを適用する
<h2><%= t('devise.sessions.new.sign_in') %></h2>
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="form-group">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control mb-3'%>
</div>
<div class="form-group">
<%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "current-password", class: 'form-control mb-3'%>
</div>
<% if devise_mapping.rememberable? %>
<div class="form-check mb-3">
<%= f.check_box :remember_me, class:'form-check-input' %>
<%= f.label :remember_me, class:'form-check-label' %>
</div>
<% end %>
<%= f.submit class: 'btn btn-primary' %>
<% end %>
<%= render "devise/shared/links" %>
ヘッダービューの切り替え
ヘルパーメソッドuser_signed_in?
を使ってログイン状態によってヘッダーの表示を切り替えます。
ルーティングも追加します。
<ul class="navbar-nav ms-auto">
<% if user_signed_in? %>
<li class="nav-item">
<% if current_user.profile.present? %>
<%= image_tag current_user.profile.thumb.url %>
<% else %>
<%= image_tag 'user.png', id: 'preview-target', size:'50x50', class: 'round-circle' %>
<% end %>
<%= link_to current_user.user_name, class: "nav-link" %>
<li class="nav-item">
<%= link_to t('devise.sessions.destroy.sign_out'), destroy_user_session_path, method: :delete, class: 'nav-link' %>
</li>
</li>
<% else %>
<li class="nav-item">
<%= link_to t('devise.sessions.new.sign_in'), new_user_session_path, class: 'nav-link' %>
</li>
<li class="nav-item">
<%= link_to t('devise.registrations.new.sign_up'), new_user_registration_path, class: 'nav-link' %>
</li>
<% end %>
</ul>
ターミナルからパスを確認することもできます。
rails routes | grep sign_out
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
メーラーを確認する
新規アカウントの登録後に確認メールが届きました。
パスワードリセット機能用のメールです。
セッションのタイムアウト
モジュールの:timeoutable
を有効化にしましたので、デフォルトで30分後アプリにログアウトされます。
タイムアウトまでの時間を伸ばすにはこの時間を変えましょう。
Devise.setup.do |config|
config.timeout_in = 30.minutes
end
終わり
簡単ですがdevise
を使ったユーザー認証でした。
編集機能についての記事もあるのであわせて見て頂けますと幸いです。
Discussion