DeviseとOmniAuthを用いると、メールアドレスを使用することなく認証機能を実装できます。 ここでは、メールアドレスを使わない方法での必要最低限の実装方法について解説します。
動作環境
この記事の内容は、以下のバージョンにより動作を確認しています。
- Ruby on Rails v4.2.6
- Devise v4.1.1
- OmniAuth v1.3.1
手順
ここでは、プロバイダとしてTwitterを利用する方法について解説します。 Facebookといった他のプロバイダも、同じような手順で追加できます。
1. Gemをインストールする
まず、利用するGemをインストールします。
以下を追記後、bundle installしてください。
Gemfile:
gem 'devise'
gem 'omniauth'
gem 'omniauth-twitter'
2. 設定ファイルを生成する
Deviseで提供されているgenerateコマンドで、Devise用の設定ファイルを生成します。
$ rails generate devise:install
create config/initializers/devise.rb
create config/locales/devise.en.yml
3. Migrationを生成する
こちらもDeviseが提供しているコマンドで、Modelを追加するMigrationを生成します。
ここでは、例としてUserモデルを追加しています。
$ rails generate devise User
invoke active_record
create db/migrate/20160615201837_devise_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
insert app/models/user.rb
route devise_for :users
4. モデルを編集する
Deviseでは、認証に関する様々な機能がモジュールとして提供されています。
コマンドで生成されたモデルには、6つのモジュールの利用が宣言されています。 そのうち、次のモジュールは使わないため削除します。
:database_authenticatable- ユーザ認証のためにパスワードをハッシュ化してデータベースに保存する
:recoverable- パスワードのリセット機能を有効化する
:registerable- フォームによるサインアップや編集・削除機能を有効化する
:validatable- メールアドレスとパスワードの組み合わせを検証する
また、:omniauthableモジュールを有効にします。
最終的に、Userモデルは次のような定義になります。
app/models/user.rb:
class User < ActiveRecord::Base
devise :omniauthable, :rememberable, :trackable
end
5. Migrationを編集する
Migrationにも編集を加えます。
メールアドレスやパスワードといった不要なカラム・インデックスを削除し、代わりにproviderとuidを追加します。
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
## Omniauthable
t.string :provider, null: false
t.string :uid, null: false
## Rememberable
t.datetime :remember_created_at
t.string :remember_token
## 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
t.timestamps null: false
end
end
end
1つ注意として、Rememberableモジュールのためにremember_tokenカラムを追加しています。
Rememberableモジュールは、ユーザのサインイン情報を記憶するためのモジュールですが、通常はpasswordカラムを参照することにより実現しています。
しかし今回はこれを削除しますので、Deviseが代替策として提供しているremember_tokenカラムの作成が必要になります。
詳しくは公式Wikiをご確認ください。
6. Migrationを反映させる
以下のコマンドでデータベースにMigrationを反映させます。
$ rake db:migrate
== 20160615201837 DeviseCreateUsers: migrating ================================
-- create_table(:users)
-> 0.0037s
== 20160615201837 DeviseCreateUsers: migrated (0.0038s) =======================
7. コールバック用のコントローラを作成する
プロバイダ(この例ではTwitter)からのコールバック時にユーザの作成・認証を行なうコントローラを実装します。 必要最低限の実装は次のようになると思います。
app/controllers/users/omniauth_callbacks_controller.rb:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
include Devise::Controllers::Rememberable
def twitter
auth = request.env['omniauth.auth']
user = User.find_or_create_by(
provider: auth.provider,
uid: auth.uid
)
remember_me(user)
sign_in_and_redirect user, event: :authentication
end
end
8. ルーティングを編集する
上記で作成したコントローラへのルーティングを設定するために、ルーティングを編集します。 また、OmniAuthを利用する場合、サインアウトへのルーティングをあわせて設定する必要があります。
config/routes.rb:
devise_for :users, controllers: {
omniauth_callbacks: 'users/omniauth_callbacks'
}
devise_scope :user do
delete :sign_out, to: 'devise/sessions#destroy', as: :destroy_user_session
end
9. APIキーを設定する
Deviseの設定ファイルに各種APIキーを設定します。
config/initializers/devise.rb:
config.omniauth :twitter, ENV['TWITTER_API_KEY'], ENV['TWITTER_API_SECRET']
動作確認
以上で必要最低限の実装は完了です。 以下のようなViewをもったページを作成し、正しく動作することを確認します。
<% if user_signed_in? %>
<%= link_to 'Sign out', destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to 'Sign in', user_twitter_omniauth_authorize_path %>
<% end %>
備考
サインイン用のページを作成する
以上の手順の場合、:authenticate_user!などで認証が必要なアクションに認証なしにアクセスしようとすると、root_pathにリダイレクトします。
これを、例えば専用のサインインページなどに振り分けたい場合は、以下のようにnew_user_session_pathを設定します。
config/routes.rb:
devise_scope :user do
get :sign_in, to: 'users/sessions#new', as: :new_user_session
delete :sign_out, to: 'devise/sessions#destroy', as: :destroy_user_session
end
この場合、Users::SessionsController#newを作成し、サインイン用のリンクを含んだページを実装することになると思います。
おわりに
ユーザ認証がOAuthのみで行なえると、ユーザとしてもセキュリティ的に安心ですし、運営者側も不要なリスクを負う必要がなくなります。 必要に応じてぜひ参考にしてください。