はじめに
オリジナルアプリにTwitter認証機能を実装する際に、いくつかハマったポイントがあったため、忘れないためにも一連の実装の流れをまとめてみたいと思います。
環境
- Ruby 2.5.3
- Ruby on Rails 5.2.3
- PostgreSQL 11.4
前提
- Deviseがインストール済みであること
- Userモデルが作成済みであること
TwitterAPIの取得
この項目に関してはこちらの記事が非常に参考になりましたので、ぜひそちらを見ていただくといいかと思います。
gemのインストール
今回必要となるgemは以下になります。
gem 'omniauth'
gem 'omniauth-twitter'
インストールしていきます。
$bundle install
Userモデルに必要なカラムの追加
今回追加するカラムは以下になります。
- uid(string) ・・・ ユーザー毎に異なる
- provider(string) ・・・ ツイッターログイン情報の保存
- name ・・・ ユーザーネーム
私の場合のTwitter認証で使用したカラムは最終的に以下になりました。
この辺はアプリによって自由に変更してください。
- uid(string)
- provider(string)
- name(string)
- email(string)
- avatar(string)
- password(string)
では追加していきます。
$rails g migration AddColumnsToUsers provider:string uid:string name:string
def change
add_column :users, :provider, :string
add_column :users, :uid, :string
add_column :users, :name, :string
end
end
忘れずにDBに反映しておきましょう。
$rails db:migrate
これでモデルの準備が整いました。
APIkeyの設定
Devise.setup do |config|
#省略
config.omniauth :twitter, ENV['API_KEY'], ENV['API_SECRET'],
callback_url:"各々のAPI取得時に設定したcallback_url"
開発環境と本番環境を分けて記述する場合には、 if Rails.env.development?
等のif文で分けて書くことで区別できます。また、APIkeyはGithubに上げないように
注意してください。
Userモデルの編集
ここで行うことは以下になります。
- Deviseのモジュールの追加
- Deviseの
omniauthable
を追加します。
- Deviseの
- findメソッドの追加
- ログインしているユーザー情報を取得します。
- ダミーのメールアドレスの準備
- Deviseでログインするにはメールアドレスが必要なので、メールアドレスを保存する必要があります。
編集後のuser.rbは以下の通りです。
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :omniauthable
#省略
def self.find_for_oauth(auth)
user = User.where(uid: auth.uid, provider: auth.provider).first
unless user
user = User.create(
provider: auth.provider,
uid: auth.uid,
name: auth.info.nickname,
email: User.dummy_email(auth),
remote_avatar_url: auth.info.image,
password: Devise.friendly_token[0, 20]
)
end
user
end
#省略
private
def self.dummy_email(auth)
"#{auth.uid}-#{auth.provider}@example.com"
end
#省略
コールバックの設定
まず、app/controllers/usersの階層にomniauth_callbacks_controller.rb
があることを確認してください。おそらくrails g devise:controllers users
をした段階で作成されるはずです。無い場合は作成してください。
$rails g controller omniauth_callbacks
omniauth_callbacks_controller.rbに以下のように編集します。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
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?
sign_in_and_redirect @user, event: :authentication
else
redirect_to new_user_registration_url
end
end
end
omniauth.authという変数に入っている情報を元にユーザーが登録されているか判別して、登録されていたらログインする、登録されていない場合は登録ページに遷移するようにします。
引用元
ユーザー認証の成功・失敗した際のフラッシュメッセージ等を追加しておくと良いと思います。
ルーティングの設定
Rails.application.routes.draw do
devise_for :users, controllers: {
registrations: 'users/registrations',
sessions: 'users/sessions',
passwords: 'users/passwords',
omniauth_callbacks: 'users/omniauth_callbacks' #ここに追加
}
これで実装部分は完了です! あとはViewで確認してみましょう。
= link_to user_twitter_omniauth_authorize_path, class: 'twitter-link' do
ツイッターでログイン
ちゃんとログインできていれば完成です。
躓いたポイント
ツイッターのDeveloperアカウントでは認証できない。
最初、私はDeveloperアカウントで何度も試して躓いていました。
試して見る際はAPIを取得したアカウントとは別のアカウントでログインできるか試してみてください。
公式ドキュメントをちゃんと読んだ方がいいですね。401(Unauthorized)エラー
私の場合はAPIkeyを誤って入力していただけだったのですが、他の記事などを見ても基本的な設定部分で間違っているケースが多い気がします。API取得時の設定やDeviseでの設定をもう一度見直してみてください。
お恥ずかしいですが、Access token & access token secret
を入力していました...
今回はこれで以上になります。