はじめに
久しぶりの更新になります。某スクールを先日卒業したChihaと申します。
某スクールにてチームで某フリマアプリのコピーを作成したため、実装物のコードについて記録を残しつつ、開発チームで共有する目的で当記事を書いています。
今回はOmniAuthを利用したGoogle、facebookユーザー認証機能について、私が行った作業を全部まとめて書いていこうと思います。
極力この記事のみで全て実装できるように丁寧な記事にしようと思います。
丁寧な記事が書けるとはとは言ってない
対象読者
- SNS認証をアプリケーションに組み込みたい方
- あれこれ色々な記事を確認しながら実装するのに疲れた方
- 某スクールの受講生
後輩受講生が見る可能性があるのでこういう記事書いていいのかな?とも思いますがその辺は考えない
そもそもの話、OmniAuthとは?
Google、Facebook、twitter等のSNSアカウントを用いてユーザー登録やログインを行ってくれるgem。
gem "omniauth"
gem "omniauth-twitter"
gem "omniauth-facebook"
のように、使いたいSNSによって"omniauth-snsによって決まった名称"のgemを導入する必要があります。
OmniAuthは、複数の外部サービスのアカウント情報を使ってユーザー登録やログインを提供します。OmniAuthはサービスごとにストラテジー(Strategies)を管理する、いわば元締めのgemです。OmniAuthのストラテジーとは、外部サービスごとにOAuth認証に必要な処理が記述されており、Rackミドルウェアとして提供されます。
ということで、やっていきましょう。
開発環境
- 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の設定変更
以下のコードを書き足します。
~~中略~~
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
にログインし、プロジェクトの選択 > 新しいプロジェクト
導入するアプリに沿ってプロジェクト名を入力し、作成します(今回は記事用のスクリーンショットなのでデフォルト名そのまま)
作成したら以下の画面に遷移するので、左上の三本線(ハンバーガーアイコン)より、ナビゲーションメニューを表示し、APIとサービス > OAuth同意画面 へと遷移し、アプリ名だけ入れて保存を押します。
保存ができたら、認証情報 > 認証情報を作成 > OAuth クライアント IDから、ID取得画面へ移動します。
今回は「ウェブ アプリケーション」を選択してください。
選ぶと色々入力項目が出ますが、承認済みのリダイレクトURIに
https://localhost:9292/users/auth/google_oauth2/callback
を入れて保存してあげましょう。
保存すると、「クライアントID、クライアントシークレット」の2つが表示されます。
この2つをRailsで使用するので控えておきます。
取得できたら、認証を利用するためのAPIを有効にしましょう。
Google+ APIの有効化
左側ナビゲーションメニューからAPIとサービス > ライブラリ へ移動
google+ で検索し、検索結果に出てくるgoogle+ APIを有効にします。
これでGoogleは完了です。
facebook認証
facebook for developersへとアクセスします。
新しいアプリの追加を押してアプリ名とメールアドレスを入力し、アプリIDを作成する。
作成したら、ベーシックへと移動し、「アプリID」「app secret」を控えておきます。
控えたら左側メニューのプロダクトの横にある「+」ボタンからプロダクト追加画面へ。
一番最初に出てくる「Facebookログイン」製品の設定を押すと、左のメニューにFacebookログインの項目が追加されます。
表示されたら、左メニュー「設定」から、OAuthリダイレクトURIを設定します。
https://localhost:9292/users/auth/facebook/callback
今回はpumaの設定に沿って以下のURIを登録します。問題なければ「変更を保存」して完了です。
何も問題なければ、これでいけると思います。
これでSNS側での設定は完了しました。続いてRails側のコード。
#機能実装
今回はdeviseのomniauth_callbackを利用します。
テーブル
devise経由で作成したusersテーブルにuid、providerの2項目を追加します。(ログイン時に認証するために保存が必要になります)
$ rails g migrate 適当な名前
して適当なmigrateファイルを作成し、uidとproviderカラムを追加する記述をします。
uidは数字だけではないのでstring型にしましょう。integer型だと保存できません。
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 |
string | null: false,unique: true | |
encrypted_password | string | null: false |
uid | string | |
provider | string |
アソシエーションや他テーブルは今回の実装に関係ないので割愛します。
##ルーティング
deviseで生成されるomniauth_callbacks_controller.rbを使用するため、コントローラを明示する記述を追加します。
Rails.application.routes.draw do
devise_for :users,controllers: {omniauth_callbacks: "users/omniauth_callbacks"}
end
Controller
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
実際の認証を行う処理部分をモデルに書いています。
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のリンクを仕込むだけです。
#見やすさのためにclassや他の記述は省いています。
= link_to user_facebook_omniauth_authorize_path do
= 'Facebookで登録する'
= link_to user_google_oauth2_omniauth_authorize_path do
= 'Googleで登録する'
クライアントIDの設定
secret.ymlに取得したクライアントID・クライアントシークレットを記載します。
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及びシークレットを読み込む記述を追加します。適当にファイル末尾に以下を記載。
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
以上になります。
今回は保存処理などに関しては書いていません。認証処理と認証完了後のデータの取得を中心に記事を書きました。
最後に
スクール卒業から身の回りに積もったあれこれを消化していたら久しぶりの記事更新になりました。まだまだ書きたい項目はあるのでじゃんじゃん更新していこうと思います。
就活も頑張ります。
まだまだ粗末な点も多いと思いますが、より良いコード、間違った点などがあればご教授頂けると幸いです。