Rails3+Devise+OmniAuthで簡単にログイン機能をつくる

2014年12月11日

以前,OmniAuthでログイン認証をつくっていたときに,Googleで調べてたらDeviseという簡単にログイン周りの機能を作成するGemがあるというので使ってみた.
目標はTwitterのアカウントでログインすること.

参考:devise と omniauth で facebook 認証をする手順
RailsでDeviseを使ってみた
[Rails] OmniAuth + Device で認証する
deviseでfacebook,twitter認証

インストール

まずはdeviseとomniauthをインストールする.

gem 'devise'
gem 'omniauth'
gem 'omniauth-twitter'
$ bundle install

deviseの初期化

deviseの初期化をする.

$ rails g devise:install
      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: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:

<%= notice %>
<%= alert %>

  4. If you are deploying Rails 3.1+ on Heroku, you may want to set:

       config.assets.initialize_on_precompile = false

     On config/application.rb forcing your application to not access the DB
     or load models when precompiling your assets.

  5. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

出てきた指示どおりにconfig/environments/development.rbとapp/views/layouts/application.html.erbに追記して,rootとなるコントローラを作成しておく.

rails g devise:viewsを実行すると,認証のための画面などが作成される.

$ rails g devise:views

[DEVISE] To select a encryption which isn't bcrypt, you should use devise-encryptable gem.

      invoke  Devise::Generators::SharedViewsGenerator
      create    app/views/devise/shared
      create    app/views/devise/shared/_links.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/reset_password_instructions.html.erb
      create    app/views/devise/mailer/unlock_instructions.html.erb

最後にOmniAuthでTwitter認証を使うために,TwitterのConsumer key等を設定する.

# config/initializers/devise.rb
  ...
  config.omniauth :twitter, 'Consumer Key', 'Consumer Secret'
  ...

これで,基本的な設定は完了.


認証用ユーザーの作成

認証用のユーザーを作成する.

$ rails g devise user

[DEVISE] To select a encryption which isn't bcrypt, you should use devise-encryptable gem.

      invoke  active_record
      create    db/migrate/20130224******_devise_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/unit/user_test.rb
      create      test/fixtures/users.yml
      insert    app/models/user.rb
       route  devise_for :users

マイグレーションファイルを開いてOmniAuthを使うための変更を加える.

class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|
      ## Database authenticatable
      #t.string :email,              :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
      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 # Only if lock strategy is :failed_attempts
      #t.string   :unlock_token # Only if unlock strategy is :email or :both
      #t.datetime :locked_at

      ## Token authenticatable
      #t.string :authentication_token

      ## Omniauthable
      t.string :username, :default => ""
      t.string :provider, :null => false, :default => "database"
      t.string :uid,      :null => false, :default => ""

      t.timestamps
    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
    #add_index :users, :authentication_token, :unique => true
  end
end

ここで大事なのが,Database authenticationに関する部分をコメントアウトしておくこと.デフォルトではemailを認証キーにしているが,Twitterの認証ではemailの情報が取得できないので,ユーザIDなど他のものをキーにして認証しないといけない.


ログイン,ログアウトへのリンクを作成

# root :to => "home#index"
# app/view/home/index.html.erb
<% if user_signed_in? %>
<%= link_to 'ログアウト', destroy_user_session_path %>
<% else %>
<%= link_to "Twitterでログインする", user_omniauth_authorize_path(:twitter) %>
<% end %>

はじめ,「Twitterでログインする」が出ていて,リダイレクト後に戻ってきて「ログアウト」が表示されていたらOK.

※モデルに後からフィールドを追加したくなったらrails g migrationを使えばよい
$ rails g migration add_omniauth_fields_to_users provider:string uid:string username:string
$ rake db:migrate

※WEBrickでSSLを使ってHTTPS通信する
Setup WEBrick to Serve SSL (HTTPS) as well as Non-SSL (HTTP) Traffic Side-by-Side

※日本語化
https://github.com/ir3/tatekoto/tree/master/config/locales