Railsで一番有名なユーザ認証機能のGemがdeviseです。
Ruby on Rails チュートリアルではユーザの認証機能をスクラッチで開発しますが、deviseを使うとカンタンにユーザの認証機能を実装することができます。deviseを使ってユーザ認証機能を実装したときのメモです。
前提条件
rails 5.0.0.1
devise 4.2.0
deviseのインストール
1. プロジェクトの作成
$ rails _5.0.0.1_ new devise_app
$ cd devise_app
詳細はRailsでWEBアプリケーションを作成するときの備忘録より
2. Gemfileを編集してインストール
Gemfileにdevise
を追加
source 'https://rubygems.org'
...
gem 'devise'
...
$ bundle install
deviseの初期設定
generateコマンドでdeviseをインストール
以下のようなメッセージが表示されるので、それどおりに設定していく
$ rails g devise:install
Running via Spring preloader in process 50039
create config/initializers/devise.rb
create config/locales/devise.en.yml
===============================================================================
Some setup you must do manually if you haven't yet:
1. Ensure you have defined default url options in your environments files. Here
is an example of default_url_options appropriate for a development environment
in config/environments/development.rb:
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
In production, :host should be set to the actual host of your application.
2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:
root to: "home#index"
3. Ensure you have flash messages in app/views/layouts/application.html.erb.
For example:
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
4. You can copy Devise views (for customization) to your app by running:
rails g devise:views
===============================================================================
1. デフォルトURLの指定
config/environments/development.rb
に以下を記載
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
2. root_urlの指定
1番で指定したURLにアクセスした際に表示されるページを指定する
まだ、ページがないのでgenerate
コマンドで作成する
$ rails g controller Home index
config/routes.rb
を以下のように修正
Rails.application.routes.draw do
root 'home#index'
end
3. flashメッセージの設定
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>DeviseApp</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
<%= yield %>
</body>
</html>
4. deviseのViewを生成
$ rails g devise:views
たくさんファイルが生成される
Userモデルの設定
登録情報を保存するためのモデルを作成していく
1. Userモデルを生成
モデルのgenerate
コマンドではなく、devise
のコマンドで生成する
$ rails g devise User
db/migrate/タイムスタンプ_devise_create_users.rb
に、以下のようなマイグレーションファイルが生成される
class DeviseCreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
デフォルトでは、
- Database authenticatable: パスワードを暗号化してDBに保存。認証はPOSTリクエスト or HTTP Basic認証
- Registerable: ユーザ自身がサインアップ・編集・削除することを許可
- Recoverable: パスワードをリセットして、それを通知
- Rememberable: Cookieでユーザのを記憶するトークンを生成・削除
- Trackable: サインイン回数・時間、IPアドレスを保存
- Validatable: Emailやパスワードのバリデーション
が、ONになっている
- Confirmable: メールで配信して、URLクリックしたら本登録
- Lockable: 一定回数サインインに失敗するとアカウントロック
- Timeoutable: 一定時間活動してないアカウントのセッションを破棄
- Omniauthable: TwitterやFacebookの認証を実装するために使用
をONにするには、以下の修正が必要
まず、UserModelを変更する
今回は、omniauthable以外全部実装してみる
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :timeoutable
end
次に、マイグレーションファイルを変更する
class DeviseCreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
t.string :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
t.string :unlock_token # Only if unlock strategy is :email or :both
t.datetime :locked_at
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
add_index :users, :confirmation_token, unique: true
add_index :users, :unlock_token, unique: true
end
end
最後に、マイグレーションコマンドを叩く
$ rails db:migrate
Viewの編集
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>DeviseApp</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<header>
<nav>
<ul>
<% if user_signed_in? %>
<li>
<%= link_to 'Edit', edit_user_registration_path %>
</li>
<li>
<%= link_to 'Logout', destroy_user_session_path, method: :delete %>
</li>
<% else %>
<li>
<%= link_to 'Sign-up', new_user_registration_path %>
</li>
<li>
<%= link_to 'Login', new_user_session_path %>
</li>
<% end %>
</ul>
</nav>
</header>
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
<%= yield %>
</body>
</html>
Confirmable - アカウント登録確認メールを送信
1. confirmableとは?
新規登録入力後確認メールを送信して、届いたメールのURLがクリックされるとログイン可能になる仕組み
2. メールの設定
config/initializers/devise.rb
に、送信に使用するメールアドレスを設定する
Devise.setup do |config|
...
config.mailer_sender = '使用するメールアドレス'
...
end
config/environments/development.rb
にメールのsftp情報を入力する
...
# mail setting
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => "smtpサーバー名",
:port => '587',
:user_name => "アカウント名",
:password => "パスワード",
:authentication => :login,
:enable_starttls_auto => true
}
end
ここで注意!
もし設定を間違えていて、535 5.7.0 authentication failed.
というエラーが出たら、ソース修正後、Railsのサーバーを必ず再起動する
どうやら、再起動しないと設定ファイルが読み込まれない
3. 届いたメールを確認する
メールを正しく設定できると、サインアップ後に登録したメールアドレス宛に有効化リンクが付いたメールが届く
リンクをクリックすると、ユーザが有効化されてログインできるようになる
app/views/devise/confirmation_instructions.html.erb
にてメールの内容を変更できる
Lockable - アカウントをロック
Locableとは?
アカウント認証を一定回数以上間違えると、アカウントロックする機能
うーん、ブルートフォースとか防げるっちゃ防げるけど、
メールリストにヒットしたユーザのアカウントを全部ロックされちゃ困るわな
単純な、嫌がらせは防げるのかな?
ひとまず、実装してみまっしょ
設定方法
config/initializers/devise.rb
で以下のような記載をする
今回は、5回ログインに失敗したら、登録したメールアドレスにアンロックのURLを送信するような設定を
maximum_attempts
の数字は、失敗してもいい回数なので4に設定(つまり5回目でNG)
...
config.unlock_strategy = :email
config.maximum_attempts = 4
...
Timeoutable - 一定時間アクセスのないセッションを破棄
Timeoutableとは?
一定時間アクセスがないセッションをタイムアウトにする機能
設定方法
config/initializers/devise.rb
にて設定
config.timeout_in
に〇〇分後にタイムアウトする時間を設定
...
config.timeout_in = 30.minutes
...
アクセス制限をかける
ここまででだいたいサインアップ・サインインの機能を実装した
しかし、全ページにアクセスできてはせっかくの認証の意味がない
そこで、Home#index
にはログインしたユーザしかアクセスできないようにする
ログインしていないユーザがHome#index
つまりroot
の画面にアクセスした場合、ログイン画面に遷移するようにせっていする
ログインしていないユーザはログイン画面に強制リダイレクト
app/controllers/application_controller.rb
にbefore_action :authenticate_user!
を追記
各コントローラー毎にも設定できる
まとめ
Railsチュートリアルで結構たいへんなアカウント認証機能づくりですが、deviseを使うとカンタンに実装できました
deviseを利用するとソーシャルログイン機能も実装できる (TODO いつか実装してみる)
Devise + CanCanCan + rolify
を組み合わせることで、ユーザの権限も管理できる (TODO いつか実装してみる)