Help us understand the problem. What is going on with this article?

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

はじめに

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

追記

こちらも参考になります。
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'

最後に

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

Hassan
フリーランスの Rails エンジニアです。Twitter でフォローしてください。
https://hassansan.me
campfirejp
国内最大の流通を誇るクラウドファンディングサービス「CAMPFIRE」の企画・開発・運営を行うスタートアップです
https://camp-fire.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした