Edited at

【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'



最後に

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