【Rails4.2.x】omniauth(twitter/facebook/github)実装まとめ

  • 102
    いいね
  • 0
    コメント

はじめに

実装する度に検索するのも面倒なので、この際にまとめます。
理解すべきところはそれについて言及しています。

追記

こちらも参考になります。
Devise+OmniAuthでユーザ認証を実装する手順

対象読者

自分のサービスにソーシャルログインを追加したい人

omniauthとは

Webアプリケーションのログイン認証を、複数のプロバイダを通して行うことができるgemです。
新規登録の際によくある、Twitter・Facebookでログインはこれを使って実装できます。

事前準備

Userモデルを作成します。
カラム名は使用したいデータに合わせて変更してください。

twitter用
rails g model user provider:string uid:string nickname:string image_url:string
github用
rails g model user name:string provider:string uid:text oauth_token:string

omniauth-twitter

Gemfilegem omniauth, gem omniauth-twitterを追加。

Gemfile
gem 'omniauth'
gem 'omniauth-twitter'

omniauth.rbを作成し、以下を記述。

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

middlewareとは?自分で作れるの?と思って調べました
Webサーバーがフレームワークとデータのやりとりをする場所です。
自作すると色々できておもしろそう。

Twitter Application Managementでキーを発行します。
そしてdirenv.envrcを作成し、管理します。

.envrcを作成
direnv edit .
.envrcを編集
export TWITTER_KEY="xxxxxxxxxxxxxxxxx"
export TWITTER_SECRET="xxxxxxxxxxxxxxxxxxxxxx"

さて、モデルから作成していきます。

model/user.rb
class User < ActiveRecord::Base

  def self.find_or_create_from_auth(auth)
    provider = auth[:provider]
    uid = auth[:uid]
    nickname = auth[:info][:nickname]
    image_url = auth[:info][:image]

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

find_or_create_from_authはDBにユーザーがいれば持ってきて、なければ作るという処理です。

次にsessionsコントローラーを作成し、以下を記述します。

controller/sessions_controller.rb
class SessionsController < ApplicationController
  def create
    user = User.find_or_create_from_auth(request.env['omniauth.auth'])
    session[:user_id] = user.id
    redirect_to root_path
  end

  def destroy
    reset_session
    redirect_to root_path
  end
end

次に、application_controller.rbにヘルパーメソッドを記述していきます。

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

helper_method :メソッド名で指定すると、そのメソッドがViewでも扱えるようになります。
ユーザーの識別やログインしているかどうかを返すメソッドを指定するとViewがすっきりします。
logged_in?!!は返り値がnilの場合、nilではなくfalseを返すようにしています。
メソッド名が真偽値であるため、falseで帰ったほうがより良いと思います。

次に、route.rbにログイン・ログアウトのルーティングを設定します。

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

  root 'homes#top'
end

最後に、Viewにログイン・ログアウト用のリンクを記述し、終了です。

views/homes/top.html.slim
- if logged_in?
  = link_to 'ログアウト', logout_path
- else
  = link_to 'Twitterでログイン', 'auth/twitter'

401が発生する場合は、twitter developerの方でアクセストークンを発行し直したり、
.envrcに不必要な空白がはいってないか確認してください。(僕はこれでした)

facebook-omniauth

試してないけど参考にされたい

instagram-omniauth

30分でinstagram-omniauth + Devise でログイン機能を実装してみる

github-omniauth

Github developer settings
上記のリンクでアプリケーションを登録します。
Homepage Urlにはhttp://localhost:3000
Authorization callback URLにはhttp://localhost:3000/auth/github/callbackと入力しましょう。
実際の運用では、本番環境用のURLを新規に作ることをオススメします。

Gemfile
gem 'omniauth'
gem 'omniauth-github'
initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET'], scope: "user,repo"
end

データ取得のscope指定はサービスに合わせて設定します。

model/user.rb
def self.create_with_omniauth(auth)
    create! do |user|
      user.provider = auth['provider']
      user.uid = auth['uid']
      user.name = auth['info']['nickname']
      user.oauth_token = auth['credentials']['token']
    end
  end

controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def callback
    auth = request.env['omniauth.auth']

    user = User.find_by(provider: auth['provider'], uid: auth['uid']) || User.create_with_omniauth(auth)
    session[:user_id] = user.id
    redirect_to root_path
  end

  def destroy
    reset_session
    redirect_to root_path
  end
end
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/route.rb
Rails.application.routes.draw do
  get 'auth/:provider/callback', to: 'sessions#callback'
  get '/logout', to: 'sessions#destroy'

  root 'homes#top'
end
views/top.html.slim
- if logged_in?
  = link_to 'Sign out', '/signout'
- else
  = link_to 'Githubアカウントでログイン', '/auth/github'

最後に

ログインはちょちょいと乗り越えて、サービスの核を作りこみましょう!

  • この記事は以下の記事からリンクされています
  • rails omniauthからリンク