技術ネタ

Rails,devise,omniauthでSNSログインを実装する

コードの修正

前提

deviseの対象となっているModelは`User`クラスとします。別なModelが対象になっている場合は適宜読み替えて下さい。

omniauth関連のgemを追加

下記のgemを追加します。

gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-twitter'
gem 'omniauth-rails_csrf_protection' # こちらについては後述

 

Userにuid,providerフィールドを追加

Userにuid, providerを追加します。

uid, providerはSNSログイン時に各SNSから発行される値です。

class AddColumnsToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :uid, :string
    add_column :users, :provider, :string
  end
end

 

User Modelのdevise設定を変更

devise omniauthableを有効にする

Userのomniauthableを有効化します。

class User < ApplicationRecord
  # 変更前
  devise :database_authenticatable, :registerable, :validatable, :recoverable

  # 変更後
  devise :database_authenticatable, :registerable, :validatable, :recoverable, :omniauthable, omniauth_providers: %i[twitter facebook]

  # 略
end

 

ログインと登録処理を実装する

authから発行された providerとuidで`User`を検索します。

存在すればSNSログイン済なので検索ヒットしたユーザーを返し、存在しなければ新たに登録します。

def self.find_for_oauth(auth)
  user = User.where(provider: auth.provider, uid: auth.uid).first

  unless user
    user = User.create( name: auth.info.name,
    provider: auth.provider,
    uid: auth.uid,
    email: auth.info.email,
    password: Devise.friendly_token[0,20] )
  end
end

 

CallBack用のControllerを追加

omniauthを導入すると、各SNSで認証完了後にコールバックが呼ばれます。

コールバック内で前述の`self.find_for_oauth`を呼びます。

正常に動作するとユーザーのインスタンスが返ってくるので、そのインスタンスを使ってログイン処理を行います。

例 ※クラス名は適宜自分のプロダクトに合わせて読み替えて下さい。

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
  callback_from :facebook
  end

  def twitter
  callback_from :twitter
  end

  private
  # コールバック処理を共通化しています
  def callback_from(provider)

    auth = request.env['omniauth.auth']
    provider = provider.to_s

    @user = User.find_for_oauth(auth)

    if @user.persisted?
      sign_in_and_redirect @user, event: :authentication
    else
      session["devise.#{provider}_data"] = auth.except("extra")
      redirect_to new_user_session_path, alert: @user.errors.full_messages
    end
  end
end

Viewを追加

※ pathメソッドの名称は各自のパスと異なる可能性があるので適宜読み替えて下さい。

omniauth-rails_csrf_protectionを入れているのでmethodをpostにする必要があります。

<%= link_to "Sign in with Facebook", user_facebook_omniauth_authorize_path, method: :post %>
<%= link_to "Sign in with Google", user_google_oauth2_omniauth_authorize_path, method: :post %>

 

SNS側の設定

Facebook

下記を参考にFacebookアプリを作成してAPIキーを取得します

Railsで Facebook ログインを実装してみた # 5. Facebook APIキーの取得

特にURLについては間違えないように設定していきます。

作成できたらアプリID、app secretを控えておきます。

Twitter

同様にTwitterもアプリを作成します

Rails5 Twitterログインをdevise+omniauthで実装 # Twitter Developer登録

※ Twitterアプリの申請については審査が入ります。アプリの説明等を英語で記載する必要があります。また、審査が降りるまでの期間がどのくらいになるか不明です。

こちらも作成完了後、API KeyとAPI secret keyを控えておきます。

環境変数に設定

ローカルの場合

いくつか方法はありますが、今回はdotenvというgemを使いました。

gem 'dotenv-rails'

gem追加後、アプリ直下に `.env` というファイルを作成します。

中身は下記のような形になります。

FACEBOOK_ID={Facebook アプリID}
FACEBOOK_SECRET_KEY={Facabook app secret}
TWITTER_API_KEY={Twitter API Key}
TWITTER_SECRET_KEY={Twitter secret Key}

さらにリポジトリに追加しないようにgitignoreにも追加します。

.env

herokuの場合

実際に動作するサーバーはherokuを使用しているので、herokuの環境変数に設定します。

設定すべくき項目は.envの内容と同じです。

 

ハマったこと

Twitter APPにCallback URL設定漏れ

Twitter APPにはCallback URLを設定する箇所があります。これを正しく設定しないとTwitter認証が正しく動きません。

またローカルで開発している段階ではローカルホストアドレスも設定しておくのが良いと思います。

さらに注意点としては、Callback URLはググった記事などからコピペするのではなく、かならず自分のroutesを確認した上で設定することです。

記事と自分のプロダクトのパスが同じとは限らないからです。

Twitter 認証でemailが取得できない

Twitterアプリ作成後、デフォルトだとemailが取得しない設定になっているので設定を変更する必要があります。

CSRF問題

認証テスト時にCSRFの問題で認証できないことがあります。これについてはRails側でgemを追加すれば解消できます。

※ 本ページの omniauth関連のgemを追加, viewを追加 項目を参照下さい。

gem 'omniauth-rails_csrf_protection'
<%= link_to "Sign in with Facebook", user_facebook_omniauth_authorize_path, method: :post %>
<%= link_to "Sign in with Google", user_google_oauth2_omniauth_authorize_path, method: :post %>

 

Cookieが大きすぎる

認証成功後、認証情報をcookieで保存するようにしていますがその内容が大きすぎてエラーになる事があります。

認証情報の内不要なものをcookieに保存しないようにします。

CallBack用のControllerを追加 のこの部分

session["devise.#{provider}_data"] = auth.except("extra")

auth に含まれる認証情報の内、extra という項目(その他の情報的なもので認証処理には不要)を除外してCookie保存しています。

 

以上です。

Pocket
LinkedIn にシェア



新規webサービスの開発の依頼ならoffテク⭐️

低コストで、Reactなどモダン言語での新規webサービス開発を承ります

-技術ネタ
-,

Copyright© off , 2020 All Rights Reserved Powered by AFFINGER5.