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

[Rails]devise、Omniauthを利用したGoogle、facebook認証を実装した

はじめに

久しぶりの更新になります。某スクールを先日卒業したChihaと申します。
某スクールにてチームで某フリマアプリのコピーを作成したため、実装物のコードについて記録を残しつつ、開発チームで共有する目的で当記事を書いています。

今回はOmniAuthを利用したGoogle、facebookユーザー認証機能について、私が行った作業を全部まとめて書いていこうと思います。
極力この記事のみで全て実装できるように丁寧な記事にしようと思います。
丁寧な記事が書けるとはとは言ってない

対象読者

  • SNS認証をアプリケーションに組み込みたい方
  • あれこれ色々な記事を確認しながら実装するのに疲れた方
  • 某スクールの受講生

後輩受講生が見る可能性があるのでこういう記事書いていいのかな?とも思いますがその辺は考えない

そもそもの話、OmniAuthとは?

Google、Facebook、twitter等のSNSアカウントを用いてユーザー登録やログインを行ってくれるgem。

Gemfile
gem "omniauth"
gem "omniauth-twitter"
gem "omniauth-facebook"

のように、使いたいSNSによって"omniauth-snsによって決まった名称"のgemを導入する必要があります。

OmniAuthは、複数の外部サービスのアカウント情報を使ってユーザー登録やログインを提供します。OmniAuthはサービスごとにストラテジー(Strategies)を管理する、いわば元締めのgemです。OmniAuthのストラテジーとは、外部サービスごとにOAuth認証に必要な処理が記述されており、Rackミドルウェアとして提供されます。

出典:RailsでSNS認証機能を実装しよう~定番gem「OmniAuth」活用法

ということで、やっていきましょう。

開発環境

  • Ruby on Rails 5.2.2
  • Ruby 2.5.1
  • haml
  • gem devise
  • gem omniauth

事前準備

使いたいSNSのAPI取得が必要です。
今回はgoogleとfacebookですね。
また、注意事項が数点あります。

導入にあたっての注意事項

この辺でハマったから記事書いたまである

google認証の注意事項

OAuthクライアントID(Railsに設定するAPIキーのようなもの)の取得に際して、承認済みのリダイレクトURIを登録する必要がありますが、きちんとしたドメインを設定したURLでないと登録ができません。
※ローカル環境のURLは普通に登録できます。できないのはdevelopment環境での〇〇.〇〇.〇〇のような、数値のみのURLとなるドメイン等になります。
そのため、今回はローカル環境のみの話になります。本番実装するならドメインを取得して登録するなどの対応が必要です。

facebook認証の注意事項

こいつも曲者です。
OAuthクライアントID(Railsに設定するAPIキーのようなもの)の取得に際して、承認済みのリダイレクトURIを登録する必要がありますが、SSL通信を行うURLのみ登録することができます。
つまり、httpsから始まるURLでの登録が必要であり、httpで始まるURLでは登録ができません。
※Railsを普通にセッティングして開発してた場合、ローカルサーバーを普通に$rails sすると、httpから始まるパスになります。
そのため、ローカルでもSSL通信となるような設定の変更が必要になります。

注意点まとめ

  • google認証では、本番環境ではきちんとしたドメインの取得が必要な場合がある
  • facebook認証では、httpsから始まるパスによるSSL通信をするURLを登録する必要がある

今回の記事ではローカルでの開発に絞った話をするため、ローカルでのSSL通信化のみ必要となります。

開発環境でのSSL通信化

Rails5 + pumaのローカル環境でSSL/HTTPSを有効にするを参考にしました。

SSL証明書の作成

今回はローカルで動くようにするだけなので適当な証明書をアプリのディレクトリ内に適当に作ります。

ターミナル
ssl証明書を置くディレクトリ $ openssl genrsa 2048 > server.key
ssl証明書を置くディレクトリ $ openssl req -new -key server.key > server.csr #色々入力を求められますが、全部適当で大丈夫です。
ssl証明書を置くディレクトリ $ openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt

作れたらpumaの設定を弄ります。

pumaの設定変更

以下のコードを書き足します。

puma.rb
~~中略~~
if ENV.fetch('RAILS_ENV') { 'development' } == 'development'
  ssl_bind 'localhost', '9292', {
    key: 'tmp/server.key',
    cert: 'tmp/server.crt'
  }
end

ssl_bindの後にはURLにしたい番号やらを書くといいです。
今回の場合は生成されるのはhttps://localhost:9292となります。

起動時の注意

SSL通信が可能なサーバーを起動する場合、$ rails sではなく、

ターミナル
$ bundle exec puma -C config/puma.rb

で起動します。
以後はこの起動コマンド及びURLにて作業することになります。

続いて認証のためのAPI取得などなど

google認証

まずはクライアントID及びクライアントシークレットを取得します。

クライアントIDの取得

Google Developer Console
にログインし、プロジェクトの選択 > 新しいプロジェクト
スクリーンショット 2019-10-18 18.24.13.png
スクリーンショット 2019-10-18 18.26.50.png
導入するアプリに沿ってプロジェクト名を入力し、作成します(今回は記事用のスクリーンショットなのでデフォルト名そのまま)
スクリーンショット 2019-10-18 18.29.49.png
作成したら以下の画面に遷移するので、左上の三本線(ハンバーガーアイコン)より、ナビゲーションメニューを表示し、APIとサービス > OAuth同意画面 へと遷移し、アプリ名だけ入れて保存を押します。
スクリーンショット 2019-10-18 18.38.27.png
スクリーンショット 2019-10-18 19.15.23.png
スクリーンショット 2019-10-18 19.19.30.png

保存ができたら、認証情報 > 認証情報を作成 > OAuth クライアント IDから、ID取得画面へ移動します。

スクリーンショット 2019-10-18 18.45.11.png
スクリーンショット 2019-10-18 18.46.54.png
スクリーンショット 2019-10-18 18.49.44.png
スクリーンショット 2019-10-18 19.11.13.png

今回は「ウェブ アプリケーション」を選択してください。
スクリーンショット 2019-10-18 19.25.22.png
選ぶと色々入力項目が出ますが、承認済みのリダイレクトURIに

https://localhost:9292/users/auth/google_oauth2/callback

を入れて保存してあげましょう。
保存すると、「クライアントID、クライアントシークレット」の2つが表示されます。
この2つをRailsで使用するので控えておきます。

取得できたら、認証を利用するためのAPIを有効にしましょう。

Google+ APIの有効化

左側ナビゲーションメニューからAPIとサービス > ライブラリ へ移動
スクリーンショット 2019-10-18 20.31.07.png

google+ で検索し、検索結果に出てくるgoogle+ APIを有効にします。
スクリーンショット 2019-10-18 20.34.12.png
スクリーンショット 2019-10-18 20.35.26.png
スクリーンショット 2019-10-18 20.37.01.png

これでGoogleは完了です。

facebook認証

facebook for developersへとアクセスします。
新しいアプリの追加を押してアプリ名とメールアドレスを入力し、アプリIDを作成する。
スクリーンショット 2019-10-18 20.43.26.png
スクリーンショット 2019-10-18 20.45.20.png
作成したら、ベーシックへと移動し、「アプリID」「app secret」を控えておきます。
スクリーンショット 2019-10-18 20.56.30.png
スクリーンショット 2019-10-21 14.31.28.png
控えたら左側メニューのプロダクトの横にある「+」ボタンからプロダクト追加画面へ。
スクリーンショット 2019-10-21 15.05.05.png

一番最初に出てくる「Facebookログイン」製品の設定を押すと、左のメニューにFacebookログインの項目が追加されます。
スクリーンショット 2019-10-21 15.07.42.png
表示されたら、左メニュー「設定」から、OAuthリダイレクトURIを設定します。

https://localhost:9292/users/auth/facebook/callback

今回はpumaの設定に沿って以下のURIを登録します。問題なければ「変更を保存」して完了です。

スクリーンショット 2019-10-21 15.35.47.png

何も問題なければ、これでいけると思います。

これでSNS側での設定は完了しました。続いてRails側のコード。

機能実装

今回はdeviseのomniauth_callbackを利用します。

テーブル

devise経由で作成したusersテーブルにuid、providerの2項目を追加します。(ログイン時に認証するために保存が必要になります)

ターミナル
$ rails g migrate 適当な名前

して適当なmigrateファイルを作成し、uidとproviderカラムを追加する記述をします。
uidは数字だけではないのでstring型にしましょう。integer型だと保存できません。

migrateファイル
class AddOmniauthToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :provider, :string
    add_column :users, :uid, :string
  end
end

書いたら

ターミナル
$ rails db:migrate

して、テーブルの準備は完了です。
最終的なテーブル構成はこんな感じに。

テーブル構成

Column Type Options
nickname string null: false
email string null: false,unique: true
encrypted_password string null: false
uid string
provider string

アソシエーションや他テーブルは今回の実装に関係ないので割愛します。

ルーティング

deviseで生成されるomniauth_callbacks_controller.rbを使用するため、コントローラを明示する記述を追加します。

routes.rb
Rails.application.routes.draw do
  devise_for :users,controllers: {omniauth_callbacks: "users/omniauth_callbacks"}
end

Controller

controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  #facebookとgoogle_oauth2の2つを定義
  def facebook
    callback_from :facebook
  end

  def google_oauth2
    callback_from :google
  end

  private

  def callback_from(provider)
    provider = provider.to_s #プロバイダを定義
    @user = User.from_omniauth(request.env['omniauth.auth']) #モデルでSNSにリクエストするメソッド(from_omniauth)を使用し、レスポンスを@userに代入
    if @user.persisted? #@userがすでに存在したらログイン処理、存在しなかったら残りの登録処理へ移行
      sign_in @user
      redirect_to root_path
    else
      #今回は複数ページに渡る登録項目があるため、情報をsessionに保存し、他のページにも持ち越せるように
      #この辺りの値は用途に合わせてアレンジしてください。
      session[:password] = @user.password
      session[:password_confirmation] = @user.password
      session[:provider] = @user.provider
      session[:uid] = @user.uid
      redirect_to registration_signup_index_path
    end
  end

end

Model

実際の認証を行う処理部分をモデルに書いています。

user.rb
class User < ApplicationRecord
  # :omniauthableの記述を追加するのを忘れないように
  devise :database_authenticatable, :registerable,
          :recoverable, :rememberable, :validatable, :omniauthable
  ~~中略~~
  # sns認証後、ユーザーの有無に応じて挙動を変更する
  def self.from_omniauth(auth)
    # uidとproviderでユーザーを検索
    user = User.find_by(uid: auth.uid, provider: auth.provider)
    if user
      #SNSを使って登録したユーザーがいたらそのユーザーを返す
      return user
    else
      #いなかった場合はnewします。
      new_user = User.new(
        email: auth.info.email,
        nickname: auth.info.name,
        uid: auth.uid,
        provider: auth.provider,
        #パスワードにnull制約があるためFakerで適当に作ったものを突っ込んでいます
        password: Faker::Internet.password(min_length: 8,max_length: 128)
      )
      return new_user
    end
  end
end

View

認証を行いたいページの適当な箇所にcallbackのリンクを仕込むだけです。

new.html.haml
#見やすさのためにclassや他の記述は省いています。
= link_to user_facebook_omniauth_authorize_path do
  = 'Facebookで登録する'
= link_to user_google_oauth2_omniauth_authorize_path do
  = 'Googleで登録する'

クライアントIDの設定

secret.ymlに取得したクライアントID・クライアントシークレットを記載します。

secret.yml
development:
  google_client_id: <%= ENV["GOOGLE_CLIENT_ID"] %>
  google_client_secret: <%= ENV["GOOGLE_CLIENT_SECRET"] %>

  facebook_client_id: <%= ENV["FACEBOOK_CLIENT_ID"] %>
  facebook_client_secret: <%= ENV["FACEBOOK_CLIENT_SECRET"] %>

devise.rbに、設定したクライアントID及びシークレットを読み込む記述を追加します。適当にファイル末尾に以下を記載。

devise.rb
config.omniauth :facebook,Rails.application.secrets.facebook_client_id,Rails.application.secrets.facebook_client_secret
config.omniauth :google_oauth2,Rails.application.secrets.google_client_id,Rails.application.secrets.google_client_secret

以上になります。
今回は保存処理などに関しては書いていません。認証処理と認証完了後のデータの取得を中心に記事を書きました。

最後に

スクール卒業から身の回りに積もったあれこれを消化していたら久しぶりの記事更新になりました。まだまだ書きたい項目はあるのでじゃんじゃん更新していこうと思います。
就活も頑張ります。

まだまだ粗末な点も多いと思いますが、より良いコード、間違った点などがあればご教授頂けると幸いです。

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
ユーザーは見つかりませんでした