Rails5で、Facebook認証を実装しよう! #rubybg

Pocket
LINEで送る

Facebook認証を利用して、Railsアプリケーションにログインできるようにしたい思います。
devise + OmniAuth というGemを利用して実装していきます。

Deviseとは

https://github.com/plataformatec/devise

Deviseは、Railsでログイン管理を簡単に行える便利なGemです。
新規登録時に認証メールを送信したり、ログイン・ログアウト機能も簡単に実装できます。

OmniAuthとは

OmniAuthは、簡単にWebアプリケーションのマルチプロバイダ認証を実装することができるGemです。
FacebookやTwitter等のSNS認証を実装する際に利用すると便利です。
それぞれに、Gemが公開されているので、今回は、Facebook用のGemをインストールをして実装していきたいと思います。

環境

Rails 5.0.1

Facebookアプリケーションの作成

Facebook Developers でアプリケーションを作成します。

「製品を追加」を選択して、「Facebookログイン」の「スタート」ボタンをクリックします。

ひとまず、設定する箇所は「有効なOAuthリダイレクトURL」です。
認証するアプリケーションのURLを設定します。
「変更を保存」をクリックします。

Deviseのインストール

次に、Deviseのインストールと設定を行っていきます。

Gemfileに下記を追加します。

gem 'devise'

bundleインストールを行ないます。

$ bundle install --path vendor/bundle --jobs=4

deviseのファイルを生成します。

$ bundle exec rails g devise:install
Running via Spring preloader in process 39790
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

こんな出力がされればOKです。

Deviseで出力されるメッセージを日本語化します。

英語版のymlファイルを、日本語版としてコピーします。

$ cp -p config/locales/devise.en.yml config/locales/devise.ja.yml

中のメッセージを日本語に置き換えます。

Userモデルを生成します。

$ bundle exec rails g devise user
Running via Spring preloader in process 13886
      invoke  active_record
      create    db/migrate/20170304210629_devise_create_users.rb
      create    app/models/user.rb
      invoke    rspec
      create      spec/models/user_spec.rb
      invoke      factory_girl
      create        spec/factories/users.rb
      insert    app/models/user.rb
       route  devise_for :users

マイグレーションの実行

$ bundle exec rake db:migrate

ログイン画面を表示します。

http://localhost:3000/users/sign_up

メールでのログイン認証画面が表示されればOKです。

認証機能の実装

Gemfileに追記します。

gem 'omniauth'
gem 'omniauth-facebook'

インストールします。

$ bundle install --path vendor/bundle --jobs=4

Userモデルに、カラムを追加します。

app/models/user.rb

bundle exec rails g migration AddColumnsToUsers uid:string provider:string

マイグレーションの実行

$ bundle exec rake db:migrate

Deviseの設定

Facebookアプリケーションの アプリIDapp secret を追記します。

config/initializers/devise.rb

Devise.setup do |config|
  ## 省略
  config.omniauth :facebook, ENV['APP_ID'], ENV['APP_SECRET']
end

Gitでソース管理したいので、直接 アプリIDapp secret を記載することは避けて、環境変数から呼び出せるようにします。

.evnに環境変数を設定

DotenvというGemを利用して環境変数を読み込んでいるのですが、導入手順はこちらで紹介しています。
RailsにDotenvを導入!環境変数を管理しよう!

Facebookアプリケーションの「設定->ベーシック」に記載されている、 アプリIDapp secret を、 .env に設定します。

APP_ID="xxxxxxxxxxxxxxxx"
APP_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxx"

:omniauthable を追記します。

app/models/user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable
end

Userモデルにメソッドを追加します。

Userモデルに認証時に、ユーザ情報を検索するメソッドを追加します。

app//models/user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable

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

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

    user
  end

  private

  def self.dummy_email(auth)
    "#{auth.uid}-#{auth.provider}@example.com"
  end
end

コールバック処理を実装

ディレクトリを作成します。

mkdir app/controllers/users

コールバックの処理を実装します。

app/controllers/users/omniauth_callbacks_controller.rb

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

  private

  def callback_from(provider)
    provider = provider.to_s

    @user = User.find_for_oauth(request.env['omniauth.auth'])

    if @user.persisted?
      flash[:notice] = I18n.t('devise.omniauth_callbacks.success', kind: provider.capitalize)
      sign_in_and_redirect @user, event: :authentication
    else
      session["devise.#{provider}_data"] = request.env['omniauth.auth']
      redirect_to new_user_registration_url
    end
  end
end

ルーティングの設定

config/routes.rb

Rails.application.routes.draw do
  # コールバック用URL
  devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }

 # ログアウト用
  devise_scope :user do
    delete :sign_out, to: 'devise/sessions#destroy', as: :destroy_user_session
  end
end

ログイン画面を表示

http://localhost:3000/users/sign_up

「Sign in with Facebook」というリンクが表示されていたらOKです。

他のviewに記載したい場合は、下記をviewに記述します。

user_omniauth_authorize_path(:facebook)

URLを読み込めません:このURLのドメインはアプリノドメインに含まれていません。
このURLを読み込むには、アプリ設定のアプリドメインにすべてのドメインとサブドメインを追記してください。

リンクをクリックして、このようなメッセージが表示されたらFacebookアプリケーションの設定「有効なOAuthリダイレクトURI」が設定できているか見直してみてください。

「http://localhost:3000」を追加しておくとローカルでも認証が行えます。

最後に、私はヘッダーに、ログイン/ログアウトのURLを実装しました。

app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>Bgclub</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
  <div>
    <% if user_signed_in? %>
        <%= link_to 'Sign out', destroy_user_session_path, method: :delete %>
    <% else %>
        <%= link_to 'Sign in', user_facebook_omniauth_authorize_path %>
    <% end %>
  </div>
    <%= yield %>
  </body>
</html>

以上で、Facebook認証の実装は完了とします。
今回は、Devise+OmniAuthでユーザ認証を実装する手順を参考にさせていただきました。
ありがとうございました!

AWSおすすめ書籍

AWSの勉強で参考になった書籍です!

AWSで質問したいことがある!

Teratail(テラテイル)

WEBエンジニア専用のQ&Aサイトです。AWSに関しての質問や回答も活発に行われています。ぜひ、会員登録をして利用してみると良いと思います(^o^)

エンジニアのためのQ&Aサイト【teratail】

Pocket
LINEで送る