#author("2018-03-12T13:28:16+09:00","default:wikiwriter","wikiwriter") #author("2018-03-12T14:58:55+09:00","default:wikiwriter","wikiwriter") &tag(Devise/Twitter認証/古い内容); *目次 [#q988ae2a] #contents *関連ページ [#na1b9ce8] *参考情報 [#sf94cf6e] -[[[*Rails*] deviseの使い方 - Qiita:http://qiita.com/cigalecigales/items/73d7bd7ec59a001ccd74]] - Twitter認証後メールパスワードを入力したあと登録できるパターン。 -[[Railsのログイン認証gemのDeviseとOmniAuth-Twitterの連携(Twitterでログインする) - Rails Webook:http://ruby-rails.hatenadiary.com/entry/20140805/1407200400]] - Twitter認証後メールアドレスだけ入力し登録できるパターン。 -[[deviseでfacebook,twitter認証 - Qiita:http://qiita.com/mosa_siru/items/9f1faa509f4d3653a1b2]] - Twitter認証後即時登録されるパターン。 *概要 [#ifa27315] -Twitterにログインしその情報をユーザーとして利用する。 *Userモデルの生成 [#iab10e2a] -Userモデルを生成する $ bundle exec rails g devise User -user.rbを以下のように編集する。参考情報と異なりconfirmableは実装せず画面上で登録が完結できるようにする。 #pre{{ class User < ActiveRecord::Base # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :lockable, :timeoutable, :omniauthable, omniauth_providers: [:twitter] end }} -マイグレーションファイルの編集 -以下ようにする。 #pre{{ class DeviseCreateUsers < ActiveRecord::Migration 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 ## Twitter認証用 t.string :provider t.string :uid t.string :username, default: "anonymous" t.timestamps end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true add_index :users, :unlock_token, unique: true end end }} -migration実行 bundle exec rake db:migrate -このままだとエラーになってログインできない。 undefined method omniauth_authorize_path *Twitterアプリケーションの登録 [#a5b66981] -https://apps.twitter.com/ からアプリケーションを登録する。 -callback_urlは開発環境と本番環境で異なるので2個登録しておくとよい。 -開発環境の場合Callback URLは次のように設定する。localhostにするとエラーになるので注意。 http://127.0.0.1:3000/users/omniauth_callbacks *Twitter認証のための準備 [#bf34e74a] **devise.rbの編集 [#h0f62ea4] -config/initializers/devise.rbを編集 #pre{{ config.omniauth :twitter, "Consumer Key", "Consumer Secret" }} -この段階で「Sign in with Twitter」からログインすると一応Twitterのログイン画面が表示される。 -しかしcallbackが設定されていないのでエラーとなる。 The action 'twitter' could not be found for Devise::OmniauthCallbacksController **コールバック用コントローラーの生成 [#ob148449] -Twitterログイン画面から戻ってきたときに呼び出される処理を行うコントローラーを生成。 bundle exec rails g controller omniauth_callbacks -内容を編集。親クラスがDevise::OmniauthCallbacksControllerなので注意。 #pre{{ class OmniauthCallbacksController < Devise::OmniauthCallbacksController def twitter @user = User.from_omniauth(request.env["omniauth.auth"].except("extra")) if @user.persisted? flash.notice = "ログインしました!" sign_in_and_redirect @user else session["devise.user_attributes"] = @user.attributes redirect_to new_user_registration_url end end end }} **Userモデルの変更 [#r6adae74] -from_omniauthとnew_with_sessionを作成する。 #pre{{ class User < ActiveRecord::Base # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :lockable, :timeoutable, :omniauthable, omniauth_providers: [:twitter] def self.from_omniauth(auth) where(provider: auth["provider"], uid: auth["uid"]).first_or_create do |user| user.provider = auth["provider"] user.uid = auth["uid"] user.username = auth["info"]["nickname"] end end def self.new_with_session(params, session) if session["devise.user_attributes"] new(session["devise.user_attributes"], without_protection: true) do |user| user.attributes = params user.valid? end else super end end end }} **ルートの設定 [#p359fbf7] -routes.rbを編集。omniauth_callbacks_controllerが呼ばれるようにする。 devise_for :users, controllers: { :omniauth_callbacks => "omniauth_callbacks" } **処理の流れ [#l9ba643b] -初回登録時Twitterログイン画面から戻りOmniauthCallbacksControllerの下の分岐から「redirect_to new_user_registration_url」が呼ばれ登録画面が表示される。 -Userのnew_with_sessionはページをまたいでTwitterのアカウントの情報(uidやらproviderやら)を保存するために必要となる。 -Twitterの場合Twitterのアカウント情報からメールアドレスを取得できないので、戻ってきてからメールアドレス、パスワードを入力し始めて登録完了となる。 #ref(sign_up.png) #ref(Devise/Twitter認証/sign_up.png) **再ログイン時の流れ [#qddd978f] -Rememberableを実装している場合、Cookieから認証情報を構築して自動的にログイン可能となる。 -ただしCookie有効期間が切れるとTwitterサイトを使った再ログインが必要。 *Twitter認証の改良 [#gbd56603] **目標 [#u7c24ff7] -直接TwitterログインリンクをクリックしTwitterのログイン画面に遷移、戻ってきてから登録ボタンを押したら登録完了とする。 -メール、パスワードの入力はなし。 **User.from_omniauthの修正 [#e502f738] -オリジナルではUser.from_omniauthのレコード生成を試み、パスワードが空のため実際は保存されないという流れになっている。ダミーパスワードを設定するとそのまま保存されてしまい、Twitterログイン後、確認してから登録という流れに鳴らない。 -whereで検索する処理とnewでダミーユーザーを生成する処理に分ける -また登録画面でパスワード未入力のエラーが表示されないようpassword_required?を変更しておく。 #pre{{ def self.from_omniauth(auth) user = where(provider: auth["provider"], uid: auth["uid"]).first return user if user user = User.new user.provider = auth["provider"] user.uid = auth["uid"] user.username = auth["info"]["nickname"] user.email = "#{auth.provider}-#{auth.uid}@example.com" user.password = Devise.friendly_token[0,20] #これが必要? user def password_required? provider.blank? && super end end }} **ログイン画面の修正 [#l0829a8d] -registrations/new.html.erbを変更。 -Twitterのログイン画面からもどってきたあと登録しようとしているTwitterユーザー名を確認し、登録ボタンを押すと実際に登録される。 #pre{{ <h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= devise_error_messages! %> <%= @user.username %>を登録します。 <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %> }}