#author("2021-05-06T06:51:50+00:00","default:src128","src128") #author("2021-12-11T05:44:17+00:00","default:src128","src128") &tag(Devise/Twitter認証); *目次 [#qde2babe] #contents *参考情報 [#x85e96d6] -[[[*Rails*] deviseの使い方(rails5版) - Qiita:https://qiita.com/cigalecigales/items/f4274088f20832252374]] -[[deviseを用いたユーザ認証作成 -Rails奮闘記①- - Farma's Study Desk:http://farma-11.hatenablog.com/entry/2018/01/02/120323]] -[[deviseによるFacebook / Twitter 認証 -Rails奮闘記②- - Farma's Study Desk:http://farma-11.hatenablog.com/entry/2018/01/03/212502]] *関連ページ [#k9a9b2c6] -[[Devise]] -[[../最もシンプルな認証機能]] -[[./古い内容]] *使用準備 [#m352dbd7] -Gemfileの編集 #pre{{ gem 'devise' gem 'omniauth-twitter' }} -サンプルモデルなどを作成 bundle exec rails g scaffold book title:string author:string summary:text -deviseをインストールする bundle exec rails g devise:install -Userモデルの作成 bundle exec rails g devise user -Userモデルの変更。confirmableは実装せず画面上で登録が完結できるようにする。omniauthableを追加。 #pre{{ class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable end }} -migrationファイルdevise_create_user.rbの変更。 #pre{{ class DeviseCreateUsers < ActiveRecord::Migration[5.1] 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 ## Twitter認証用 t.string :provider t.string :uid t.string :username, default: "anonymous" 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 }} -migration実行 bundle exec rails db:migrate *Twitterアプリケーションの登録 [#a5b66981] -https://apps.twitter.com/ からアプリケーションを登録する。 -callback_urlは開発環境と本番環境で異なるので2個登録しておくとよい。 -開発環境の場合Callback URLは次のように設定する。localhostにするとエラーになるので注意。 http://127.0.0.1:3000/users/omniauth_callbacks *Twitter認証のための準備 [#z114b504] **devise.rbの編集 [#bb5d6965] -config/initializers/devise.rbを編集 -config/initializers/devise.rbを編集(ここで登録した"twitter"がコールバックで呼ばれるメソッドになる?) config.omniauth :twitter, "Consumer Key", "Consumer Secret" -この段階で「http://localhost:3000/users/sign_in」にアクセスし、「Sign in with Twitter」からログインすると一応Twitterのログイン画面が表示される。 -しかしコールバックが設定されていないのでラーになる。 #pre{{ The action 'twitter' could not be found for Devise::OmniauthCallbacksController }} **コールバック用コントローラーの生成 [#hf94145f] -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モデルの変更 [#b9391b71] -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, # :confirmable, :lockable, :timeoutable, :omniauthable, omniauth_providers: [:twitter] :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"] # user.email = Devise.friendly_token[0,20] user.email = "#{auth.provider}-#{auth.uid}@example.com" user.password = Devise.friendly_token[0,20] #これが必要? end end def remember_me # http://stackoverflow.com/questions/14417201/how-to-automatically-keep-user-remembered-in-devise true 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 def password_required? super && provider.blank? end def email_required? super && provider.blank? end end }} **ルートの設定 [#d05478c3] -routes.rbを編集。omniauth_callbacks_controllerが呼ばれるようにする。 #pre{{ devise_for :users, controllers: { :omniauth_callbacks => "omniauth_callbacks" } }} **画面の修正 [#s1ff7bfd] -application.html.erbの修正 #pre{{ <!DOCTYPE html> <html> <head> <title>Rails5DeviseTwitterDemo</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> <% if user_signed_in? %> <strong<%= link_to current_user.username, pages_show_path %></strong> <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %> <% else %> <%= link_to 'ログイン', user_twitter_omniauth_authorize_path %> <% end %> </nav> </header> <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> <%= yield %> </body> </html> }} -ログインしていない場合は、「ログイン」リンクが表示される。クリックされるとTwitter認証画面にとぶ。 -ログインしている場合はユーザー名と「ログアウト」リンクが表示される。 -初回の登録とそれ以降のログインに差は無い。 *ビューの変更 [#eefbc6a5] -Deviseのビューをカスタマイズする場合以下のコマンドを実行 bundle exec rails g devise:views *Tips [#g6d40a04] **認証済みユーザーでないと表示できないページ [#dc821969] -例えば認証済みユーザーでないとログインできないページ。 #pre{{ class UsersController < RegularController include ApplicationHelper #http://stackoverflow.com/questions/7458723/using-devise-to-create-private-profiles ユーザー以外がアクセスするとリダイレクト before_action :verify_owner, only: [:show, :edit, :destroy] def verify_owner redirect_to root_url unless current_user.username == params[:id] end }} *トラブルシューティング [#h3f33ae5] **急にログインできなくなった [#hc13f9bc] -2018年6月、Twitter側の仕様変更により設定されたcallback_urlを正しく送信しないとログインできなくなった模様。 -これには以下の変更が必要。 -Twitter Appの変更。本番のほかテスト用のcallbackを追加しておかないと開発環境でログインできなくなる。 http://本番サイトのURL/users/auth/twitter/callback http://localhost:3000/users/auth/twitter/callback -アプリ側の設定。callback_urlの設定は本番と開発環境で切り替える必要あり。 #pre{{ Devise.setup do |config| config.omniauth :twitter, "TWITTER_CONSUMER_KEY", "TWITTER_CONSUMER_SECRET", callback_url: 'http://localhost:3000/users/auth/twitter/callback' end }} -callback urlはroutesでcallbackをgrepするとわかる。 #pre{{ $ bundle exec rake routes | grep callback user_twitter_omniauth_callback GET|POST /users/auth/twitter/callback(.:format) }} **Twitterでログインボタンを押すと画面に「Not found. Authentication passthru」とだけ表示される [#j7a92eea] -2021/05/06(木)bundle updateで発生。 -omniauthのバージョン2.0以降と1.9で互換性がないっぽい。以下のようにomniauthのバージョンを指定する #pre{{ gem 'devise' gem 'omniauth', '1.9.1' gem 'omniauth-twitter' }} -omniauthはomniauth-twitter依存関係で?自動インストールされていたものだが上記の設定が有効のようだ。