Edited at

Railsでomniauth-twitterを使ってTwitter認証をする(2018/10)


概要

RailsのTwitterアカウントでの連携ログインについて、少しハマったのでメモしつつ、解決方法を提案できたらと思います。

TwitterAPIの仕様が数ヶ月前に変更されたあとの記事が少なく感じました(2018/10現在)。

また、deviseなるものとomniauth-twitterを連携させたものがあるようですが、今回はomniauth-twitter単体での実装です。また、作ったアプリケーションはHerokuにデプロイするところまで書きたいと思います。


開発環境

macOS High Sierra v10.13.6

ruby 2.5.1

rails 5.2.1

direnv

Heroku


準備

RailsやRubyの導入は省きます。


direnv

ディレクトリごとに環境変数を設定できるコマンドラインツールです。


導入


  • macOS

    Homebrewが入っているなら、コマンドひとつでインストールできます。

$ brew install direnv

インストール後は忘れずに「.bashrc」に設定を書きます。

$ echo 'export EDITOR=vim' >> ~/.bashrc

$ echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
$ source ~/.bashrc

詳しい使い方は次のURLを参照してください。

https://www.softantenna.com/wp/review/direnv/


Heroku

言わずとしれたデプロイサイト。railsアプリをpushするだけでデプロイが終わっちゃう驚き。

ローカル環境でOK!って人は飛ばしてください。

Herokuを導入する以前にgitを導入する必要があるんですが、ここでは省略します。

Herokuは次のURLからダウンロードしてください。

https://devcenter.heroku.com/articles/heroku-cli


TwitterAPI

個人的にちょっと厄介なこいつ。2018年9月の仕様変更によってAPIの使用に審査が必要になって、使用目的とか取得したデータの扱いとかを300文字以上の英語で送ります。Google翻訳を駆使したりしてがんばります。

APIの審査についてのURLです。ちなみに私は審査を出した当日に承認されました(2018/10)。

https://qiita.com/tdkn/items/521686c240b0c5bc6207

【重要】TwitterAPIの設定なんですが、CallBack_URLを適切に指定しないとエラーでます。

これ、意外とハマるんじゃないかと思います。

omniauth-twitterのみの場合、callback_urlは

http://localhost:3000/auth/twitter/callback

とかですね。

deviseをかませる場合少し違った気がします。

どこぞのQiita記事でlocalhostはcallback_urlに指定できないとか書いてたのでそれは間違いだって言いたいです。

TwitterAPIのCallBackについて次の記事を参考にしました。

https://saruwakakun.com/memo/omniauth-twitter


ローカル導入

まずは、ローカルでの構築を行っていきます。


新規アプリ作成とGem導入

$ rails new twitter-auth

$ cd twitter-auth/

twitter-authというアプリ名で作成します。次にGemfileを編集します。

gem 'omniauth'

gem 'omniauth-twitter'

Gemfileを編集したので忘れずにbundle installをします。

$ bundle install


APIキーの登録

用意したTwitterAPIを環境変数に設定します。

$ direnv edit .

vimが開きます。

vimの詳しい使い方についてはコチラ。

とりあえず、「i」キーを押してINSERTモードに変更して

export TWITTER_KEY="your_twitter_api_key"

export TWITTER_SECRET="your_twitter_api_secret"

書き終えたら「Esc」キーでINSERTモードを抜けて、

「:wq」と入力します。するとターミナルに戻ります。

環境変数はGitとかで公開してはダメなので、「.gitignore」に追記します。

$ echo ./.envrc >> .gitignore

次に、設定した環境変数をomniauthに設定します。ファイルが無いので新規作成して次を記述します。


config/initializers/omniauth.rb

Rails.application.config.middleware.use OmniAuth::Builder do

provider :twitter,
ENV["TWITTER_KEY"],
ENV["TWITTER_SECRET"]
end


Userモデル作成

まずはモデルを作成します。

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

次にモデルの定義です。引数のauthはTwitterAPIのレスポンスデータで、様々な情報が格納されている。


app/model/user.rb

class User < ApplicationRecord

def self.find_or_create_from_auth(auth)
provider = auth[:provider]
uid = auth[:uid]
user_name = auth[:info][: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


この他にもデータを取得したい場合は次の一覧から適切な変数を指定することでデータを取得できる。

https://github.com/arunagw/omniauth-twitter#authentication-hash

ex) ログインした人のTwitterURLをtwitter_urlに格納する。

twitter_url = auth[:info][:urls][:Twitter]


Login/Registerコントローラ作成

ログイン、ログアウトに使うSessionコントローラを作成します。

$ rails g controller sessions

そして次を記述します。


app/controller/sessions_controller.rb

class SessionsController < ApplicationController

def create
user = User.find_or_create_from_auth(request.env['omniauth.auth'])
session[:user_id] = user.uid
flash[:notice] = "ユーザ認証が完了しました。"
redirect_to root_path
end

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



ヘルパーメソッドの記述

current_user(ログイン中のユーザ情報)の取得やログイン中かどうかを返すヘルパーメソッドを定義します。


app/controller/application_controller.rb

class ApplicationController < ActionController::Base

protect_from_forgery with: :exception
helper_method :current_user, :logged_in?, :authenticate

private

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

def logged_in?
!!session[:user_id]
end

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



viewの設定

viewを定義します。今回は、pagesのindexをroot_pathとして、showをログインが必要なページとします。

rails g controller Pages index show

まずは、全体に適用するviewとして、

部分を下に変更してください。


app/view/layout/application.html.erb

<body>

<header>
<% if logged_in? %>
<%= link_to 'Logout', '/signout' %>
<% else %>
<%= link_to 'Twitter Login', '/auth/twitter' %>
<% end %>
</header>
<% if flash[:notice] %>
<div class="notice">
<%= flash[:notice]%>
</div>
<% end %>
<%= yield %>
</body>

ぶっちゃけ、indexとshowは何も書かなくていいような気がするんですけど、一応わかりやすくするために書いてます。


app/view/pages/index.html.erb

<h1>TwitterAuthTest</h1>

<p>Find me in app/views/pages/index.html.erb</p>
<%= link_to 'User Page', '/pages/show' %>


app/view/pages/show.html.erb

<% if logged_in? %>

<h1>こんにちは、<%= current_user.user_name %>さん</h1>
<p>ユーザー用ページです。</p>
<% else %>
<p>ログインしてください</p>
<% end %>


routesの設定

routesの設定です。


config/routes.rb

Rails.application.routes.draw do 

root 'pages#index'
get 'pages/show'
get '/auth/:provider/callback', to: 'sessions#create'
get '/signout', to: 'sessions#destroy'
end


ローカルで動かす

以上で導入は完了です。ローカルで動かすためにはマイグレーションをするのを忘れないでください。

$ rails db:migrate

$ rails s


起動画面

起動画面はこんな感じです。

スクリーンショット 2018-10-20 4.15.07.png

Twitterでログインをしたら。

スクリーンショット 2018-10-20 4.15.55.png

User Pageをクリック。

スクリーンショット 2018-10-20 4.15.37.png

(一部隠してます)


Herokuにデプロイ

Herokuにデプロイしてみます。


データベースシステムの変更

まず、現在使用しているSQLite3はHerokuで使えない仕様なので、PostgreSQLを使うようにGemを変更します。


  • 上の方にある「gem 'sqlite3'」は削除するか、先頭に#をつけてコメントアウトしましょう。

  • 「group :development do」の中に「gem 'sqlite3'」を書きます。

  • 「group :production do」を追記して中に「gem 'pg'」を書きます。(endを忘れずに書きます。)

これは、データベースシステムを開発環境ではSQLite3を使って本番環境 (Heroku)ではPostgreSQLを使いますという意味です。

.

.
# gem 'sqlite3'
group :development do
.
.
gem 'sqlite3'
end

group :production do
gem 'pg'
end
.
.

今後、ローカルで開発するときのためにオプションをつけてbundle installします。

$ bundle install --without production

Rails Tutorialでもおなじみのこれです。groupがproductionのものはローカルにインストールしないという意味です。


いざデプロイ

herokuにデプロイする準備ができたのでデプロイします。

$ heroku create [your_heroku_app_name]

$ git add .
$ git commit -am "init"
$ git push heroku master
$ heroku run rails db:migrate
$ heroku config:set TWITTER_KEY=your_twitter_api_key
$ heroku config:set TWITTER_SECRET=your_twitter_api_secret

TwitterAPIのページでCallBack_URLを設定します。これがないとエラー吐きます。

CallBackに以下のリンクを追加します。

https://[your_heroku_app_name].herokuapp.com/auth/twitter/callback

うまくデプロイできれば次のURLでアプリケーションが動いてるところを見ることができます。

https://[your_heroku_app_name].herokuapp.com/


ハマったポイント

ここから恥ずかしい話になります。

これを実装するのに3日ほどかかりました。なぜかというと、400エラーやら403エラーに襲われたからです・・・。

もしかしたら同じようなエラーで困っている人のために解決法を書いておきます。


400エラー

私の場合、TwitterのAPIキーがうまく設定できておらず、APIリクエストを投げる際にAPIキーを送れていなかったときに出ました。

direnvの設定で.bashrceval "$(direnv hook bash)"を書き忘れていたおかげでrailsが.envrcを読まないという原因でした。


403エラー

TwitterAPi設定で、CallBackURLを正しく指定していなかったときに発生しました。

ローカルで開発の場合は、

http://localhost:3000/auth/twitter/callback

http://127.0.0.1:3000/auth/twitter/callback

この2つを設定しておきましょう。

Herokuなどにデプロイした場合も、その都度callback_urlを設定するのを忘れないようにしましょう。


まとめ

Railsにomniauth-twitterを用いたTwitter連携ログイン機能について軽く説明を交えつつ実装方法を書きました。

Rails初心者が書いた&コピペなので間違ったコードや間違った説明などしている所あるかもしれません。

今回の開発をgithubに上げました。

https://github.com/white0221/twitter_auth_on_rails

最後まで読んでいただきありがとうございました。

開発の助けになれば幸いです。


参考

https://github.com/arunagw/omniauth-twitter

https://qiita.com/puremoru0315/items/f1d459b663fd3b715dee

https://qiita.com/ntkgcj/items/c3108c19fb64acc9dd8d