RailsでのTwitter認証


初めて使ったTwitter APIによるログイン機能の実装

今回、開発中のWebアプリで初めてTwitter APIによるログイン機能の実装に挑みました。その備忘録として残していきます!

開発環境

Ruby 2.4.1
Rails 5.1.5
Heroku

Twitter上での設定(本番環境)

Callback URL:[自分のサイトのリンク]/auth/twitter/callback

必要なgemを追加

Gemfile
.
.
.
gem 'omniauth'
gem 'omniauth-twitter'
.
.
.

追加したら忘れずに

$ bundle

Twitterでの設定

https://apps.twitter.com/app/new で設定をする。ローカルで動かすときのためにWebsiteにはhttp://localhost:3000 ではなく、http://127.0.0.1:3000 と書かないとうまく行きません。
あと、Callback URLはhttp://127.0.0.1:3000/auth/twitter/callback にしておく。
ここで取得できるAPI KeyとAPI Secretは後々使うのでメモしておく。

API KeyとAPI Secretを書くためのファイルを作成

先程取得したAPI KeyとAPI SecretはTwitter APIを使う上で必須だけど、Githubに上げてはいけないので、専用ファイルを作成する。

/.env
APP_ID=XXXXXXXXXXXXXXXXXXXXXXXXX
APP_SECRET=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY

忘れないように.gitignoreに追加する。

.gitignore
.
.
/.env
.
.

omniauth.rbを作成し、API KeyとAPI Secretが参照されるようにする

/config/initializers下にomniauth.rbというファイルを新規で作成し、以下のように記述する

/config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, ENV['APP_ID'], ENV['APP_SECRET']
end

Userモデルを作成

$ rails g model user provider:string uid:string user_name:string image_url:string

ログイン/新規登録用の処理をモデルに書く

/app/models/user.rb
class User < ApplicationRecord
  def self.find_or_create_from_auth(auth)
    provider = auth[:provider]
    uid = auth[:uid]
    user_name = auth[:info][:user_name]
    image_url = auth[:info][:image]

    self.find_or_create_by(provider: provider, uid: uid) do |user|
      user.user_name = user_name
      user.image_url = image_url
    end
  end
end

もし、DBにユーザー情報があれば取得し、なければ新規で作成するアクション。

ログイン/新規登録用のコントローラーを作成

$ rails g controller sessions

そして以下の内容を記述。

/app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def create
    user = User.find_or_create_from_auth(request.env['omniauth.auth'])
    session[:user_id] = user.id
    flash[:notice] = "ユーザー認証が完了しました。"
    redirect_to root_path
  end

  def destroy
    reset_session
    flash[:notice] = "ログアウトしました。"
    redirect_to root_path
  end
end

ユーザー情報があればそれをfindし、なければ新規にcreateしてユーザーを得る処理を行っている。callback後にちゃんと認証が完了したか確認するために、flashにそれぞれメッセージを格納している(ここはお好み次第)

ヘルパーメソッドを追加

/app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  helper_method :current_user, :logged_in?

  private

  def current_user
    return unless session[:user_id]
    @current_user ||= User.find(session[:user_id])
  end

  def logged_in?
    !!session[:user_id]
  end

  def authenticate
    return if logged_in?
    redirect_to root_path, alert: "ログインしてください"
  end
end

ルーティングを設定する

/config/routes.rb
Rails.application.routes.draw do
  get '/auth/:provider/callback', to: 'sessions#create'
  get '/logout', to: 'sessions#destroy'

  root 'home#top'
.
.
.
end

view側でflashを表示する

app/views/layouts/application.html.erb
<body>
  <% if flash[:notice] %>
    <div class="notice">
      <%= flash[:notice]%>
    </div>
  <% end %>
  <%= yield %>
</body>

これでローカルでは動くはずです!!次は本番環境!

Herokuにデプロイする

脳筋コミットでいいなら以下のようにする。(ブランチ切ってる前提)

$ git add .
$ git commit -m "Twitter認証機能を実装"
$ git push origin [branch名]
$ git checkout master
$ git merge [branch名]
$ git push origin master
$ git push heroku

環境変数を使ってAPI_KeyとAPI_Secretを渡す

これ割と忘れがちなので、注意。

$ heroku config:set APP_ID=XXXXXXXX...
$ heroku config:set APP_SECRET=YYYYY...

さあこれで本番環境でもうまくいくはず!!と思ったらうまくいかないアクシデント...
半日悩んだ結果、これを忘れてました...

$ heroku run rails db:migrate

マイグレーションの実行忘れ...本当に恥ずかしい...

最後に

なんだかんだでこれがQiita最初の記事です。わかりにくいところや表現が間違っているところもあるかもしれませんが、そこはぜひご指摘していただければと思います。
これからたくさんアウトプットしていこうと思います!!よろしくお願いします!