1. zenizh

    Posted

    zenizh
Changes in title
+RailsでDevise+OmniAuthでユーザ認証を実装する手順
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,290 @@
+
+Ruby on Railsアプリケーションに、以下の認証方法を実装する。
+今回は1→2の順序で実装する。
+
+1. メールアドレス
+2. OAuth(Facebook/Twitter)
+
+## 動作環境
+
+- Ruby on Rails 4.1.1
+- Devise 3.3.0
+- OmniAuth 1.2.2
+
+## 全体の概要
+
+先に以下の記事に目を通すことで、全体の概要を把握することができる。
+
+- http://qiita.com/mosa_siru/items/9f1faa509f4d3653a1b2
+- http://qiita.com/ytkt/items/d78841f7dea5e29f38ee
+- http://easyramble.com/implement-devise-and-ominiauth-on-rails.html
+- https://github.com/plataformatec/devise/wiki/OmniAuth%3A-Overview
+
+## 1. メールアドレスによる認証の実装
+
+### Gemfileの編集
+
+```ruby:Gemfile
+gem 'devise'
+```
+
+### インストール
+
+```
+$ bundle install
+```
+
+### Deviseの各ファイルを生成
+
+```
+$ rails g devise:install
+```
+
+### Deviseを日本語化
+
+`config/locales/devise.en.yml`を`devise.ja.yml`にリネームし、以下の内容をコピペする。
+もちろんRailsアプリ自体も日本語化しておく必要がある。
+
+- [devise-i18n/ja.yml at master · tigrish/devise-i18n](https://raw.githubusercontent.com/tigrish/devise-i18n/master/locales/ja.yml)
+
+```yaml:config/locales/devise.ja.yml
+ja:
+ devise:
+ confirmations:
+ confirmed: アカウントを登録しました。
+ send_instructions: 登録方法を数分以内にメールでご連絡します。
+ send_paranoid_instructions: メールアドレスが登録されていれば、数分以内にアカウントを確認する方法が記載されているメールが届きます。
+
+ :
+```
+
+### Userモデルを生成
+
+Deviseのジェネレータを利用することで、あらかじめモジュールが定義されたモデルファイルを生成することができる。
+
+```
+$ rails g devise user
+```
+
+### 利用するモジュールを編集
+
+Userモデルでは、`devise`メソッドによりどのモジュールを利用するかを定義できる。
+
+```ruby:app/models/user.rb
+# Include default devise modules. Others available are:
+# :confirmable, :lockable, :timeoutable and :omniauthable
+devise :database_authenticatable, :registerable,
+ :recoverable, :rememberable, :trackable, :validatable
+```
+
+利用できるモジュールについてはREADMEを参照。
+
+- https://github.com/plataformatec/devise
+
+### マイグレーションの実行
+
+`rails g devise user`したときに`db/migrate/xxx_devise_create_users.rb`という名前でマイグレーションファイルも生成されている。
+これをDBに適用する。
+
+```
+$ rake db:migrate
+```
+
+### サインアップフォームの表示
+
+以上で、`http://〜/users/sign_up`にアクセスするとフォームが表示される。
+この時点でユーザ登録ができる状態になっている。
+
+## 2. OAuthでの認証
+
+### Gemfileの編集
+
+```ruby:Gemfile
+gem 'omniauth'
+gem 'omniauth-facebook'
+gem 'omniauth-twitter'
+```
+
+### インストール
+
+```
+$ bundle install
+```
+
+### カラムの追加
+
+OmniAuthでは`uid`(一意のID)と`provider`(FacebookやTwitterなど)をカラムとして利用する。
+
+```
+$ rails g migration AddColumnsToUsers uid:string provider:string
+```
+
+### マイグレーションの実行
+
+```
+$ rake db:migrate
+```
+
+### APIキーの取得
+
+#### Facebook
+
+以下よりアプリケーションを作成する。
+
+- [Facebook Developers](https://developers.facebook.com/)
+
+作成が完了したら、設定より「Add Platform」→「Website」を選択する。
+サイトURLにURLを入力する(例:`http://192.168.33.10:3000/`)。
+
+#### Twitter
+
+以下よりアプリケーションを作成する。
+
+- [Twitter Application Management](https://apps.twitter.com/)
+
+作成が完了したら、「Settings」より以下の設定を行なう。
+
+1. Callback URL
+ - 例:`http://〜/users/auth/twitter`
+2. 以下にチェックを入れる:
+ - Allow this application to be used to Sign in with Twitter
+
+##### 参考
+
+- http://stackoverflow.com/questions/7086970/devise-omniauth-and-twitter
+
+### Deviseの設定
+
+上記で取得したプロバイダの各キーを設定する。
+開発/ステージング/本番環境と分ける場合は`Rails.env.production?`などを用いて振り分ける。
+
+```ruby:config/initializers/devise.rb
+Devise.setup do |config|
+ # ...
+
+ config.omniauth :facebook, 'App ID', 'App Secret'
+ config.omniauth :twitter, 'API key', 'API secret'
+end
+```
+
+こちらも、実際の運用ではハードコーディングせず`dotenv`などに書いた方がよいでしょう。
+
+### Userモデルにモジュールを追加
+
+`devise`メソッドに`:omniauthable`を追加する。
+
+```ruby:app/models/user.rb
+devise :database_authenticatable, :registerable,
+ :recoverable, :rememberable, :trackable, :validatable, :omniauthable
+```
+
+### Userモデルにfindメソッドを実装
+
+`uid`と`provider`の組み合わせは一意であり、これによりユーザを取得する。
+レコードに存在しない場合は作成する。
+
+```ruby:app/models/user.rb
+class User < ActiveRecord::Base
+ # ...
+
+ def self.find_for_oauth(auth)
+ user = User.where(uid: auth.uid, provider: auth.provider).first
+
+ unless user
+ user = User.create(
+ uid: auth.uid,
+ provider: auth.provider,
+ email: User.dummy_email(auth),
+ password: Devise.friendly_token[0, 20]
+ )
+ end
+
+ user
+ end
+
+ private
+
+ def self.dummy_email(auth)
+ "#{auth.uid}-#{auth.provider}@example.com"
+ end
+end
+```
+
+メールアドレスでの認証も実装している場合、OAuthでの認証時もメールアドレスを保存する必要となる。
+ここでは、`uid`と`provider`の組み合わせが一意なことを利用して、`self.dummy_email`のように生成している。
+
+#### 参考
+
+- http://stackoverflow.com/questions/18504308/getting-omniauth-facebook-and-omniauth-twitter-work
+- http://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook-and-linkedin/
+- http://easyramble.com/devise-and-omniauth-specs.html
+
+### Userコントローラにコールバック処理を実装
+
+`provider`と同じ名前のメソッドを定義する必要がある。
+ただ、基本的に各プロバイダでのコールバック処理は共通しているので、`callback_from`メソッドに統一している。
+
+```ruby:app/controllers/users/omniauth_callbacks_controller.rb
+class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
+ def facebook
+ callback_from :facebook
+ end
+
+ def twitter
+ callback_from :twitter
+ end
+
+ private
+
+ def callback_from(provider)
+ provider = provider.to_s
+
+ @user = User.find_for_oauth(request.env['omniauth.auth'])
+
+ if @user.persisted?
+ flash[:notice] = I18n.t('devise.omniauth_callbacks.success', kind: provider.capitalize)
+ sign_in_and_redirect @user, event: :authentication
+ else
+ session["devise.#{provider}_data"] = request.env['omniauth.auth']
+ redirect_to new_user_registration_url
+ end
+ end
+end
+```
+
+### ルーティング処理
+
+以下のように、OAuthのコールバック用のルーティングを設定する。
+
+```ruby:config/routes.rb
+Rails.application.routes.draw do
+ devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
+
+ # ...
+end
+```
+
+### 認証用リンクを追加
+
+以下によりリンクが生成される。
+これをビューの任意の位置に記述する。
+
+```ruby
+user_omniauth_authorize_path(:facebook)
+user_omniauth_authorize_path(:twitter)
+```
+
+## メモ
+
+### persisted?メソッドについて
+
+`.persisted?`は、レシーバがデータベースに保存済みかどうかを確認する。
+上の例では、保存に失敗したら`users/sign_up`にリダイレクトしている。
+
+- http://railsdoc.com/references/persisted%3F
+- http://stackoverflow.com/questions/9211548/rails-3-1-devise-oauth-for-facebook-routing-confusion
+
+## その他の参考記事
+
+- http://railsgirls.jp/devise/
+- http://easyramble.com/devise-on-rails.html