Webとデザインのあれこれ

プログラミングとUIデザインの学習記録です。

OAuthについて

OAuthについて

OAuthとは、第三者となるアプリケーションに対して安全にアクセス権限を提供するためのプロトコルのことです。OAuthを利用すると、例えばTwitterFacebookなどのSNSからログインすることが可能となります。

本記事ではgemのOmniAuthを利用してGitHub認証をBookアプリに実装します。

本記事の前提

内容に入る前に、まずアプリ作成の流れなどを振り返ります。

  1. Railsの教科書』内で紹介されていたBookアプリを作成
  2. 日本語に対応するためにgemi18nを実装
  3. ページネーション機能をgemkaminariで実装
  4. ログイン・ログアウト機能をgemdevisedevise-i18nで実装
  5. GitHubによるログイン機能をgemOmniAuthで実装 ←今日はここです!
  6. ActiveStorageによるプロフィール画像のアップロード機能実装

deviseを利用することで、メール認証など一旦ユーザー認証の機能は追加済みです。

DBにはBookとUserのテーブルが存在しており、モデルの作成後、Userテーブルにカラムの追加はしておりません。

f:id:b_leiu:20190517190721p:plain:w400

OmniAuth導入にあたっての補足

基本的にこちらの記事を参考にして進めました。 こちらの内容通りに進めれば問題なく実装できるかと思います。

大枠として、プロセスは以下のようなイメージです。

  1. GitHub連携の準備のため、GitHub上で"Client ID"と"Client Secret"の取得
  2. OmniAuthのインストール
  3. DBテーブルへのカラムの追加
  4. app/models/user.rbへのメソッド追加
  5. dotenv-railsをインストールし、.envファイルを作成して"Client ID"と"Client Secret"を記述
  6. コールバック処理のコントローラを作成する
  7. config/routes.rbとconfig/initializers/devise.rbの修正
  8. viewsファイルの修正

一部補足事項がありますのでこちらの記事で紹介いたします。

3. DBテーブルへのカラムの追加

deviseとomniauthを同時にインストールする場合などは、記事通りに実行すれば問題ありません。 私は既ににdeviseのインストールと実装を済ませていたので、必要なカラムを追加してマイグレーションファイルを確認する必要がありました。

OmniAuth利用に必要なカラムは以下の2つ。

  • uidprovider(この場合はGitHubですね!)

uidproviderについてはDBのデータを検索するメソッドで必要になるため、テーブルに存在していない場合追加してあげましょう。

# uidとproviderの追加
$ rails g migration AddUidToUser uid:integer provider:string

また、必須ではないのでがログイン画面でユーザー名を表示したい場合などに必要なusernameもしくはnameを登録する場合があります。これはoAuthというよりdeviseのトピックになりますね。

deviseを利用すると、認証に必要なデータとしてデフォルトでemailとパスワードが利用できますが、それ以外のカラム(代表的なのがusernameです)をDBに追加して認証に利用する場合、前回の記事でも紹介したstrong parametersの仕組みを考慮する必要があります。

# usernameの追加
$ rails g migration AddUserameToUser username:string:uniq #ユニークにするために:uniqを使用
$ rails db:migrate

application_controller.rbのbeforeフィルターに別途処理を記述しましょう。以下の記述を忘れるとstrong parametersによりエラーが発生します。

# application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
  end
end

また、usernameを追加した場合viewsについてもカスタマイズする必要があります。

詳細は公式1公式2、そして過去記事をご確認ください。

4. app/models/user.rbへのメソッド追加

Modelに様々なメソッドを追加するのですが、特に以下の処理は重要です。

uidとproviderによりDBを検索して、値が存在しない場合は、新規でユーザーインスタンスを作成するというメソッドですね。

# app/models/user.rb
def self.find_for_github_oauth(auth, signed_in_resource=nil)
user = User.find_by(provider: auth.provider, uid: auth.uid)

    unless user
      user = User.create(provider: auth.provider,
                      uid:      auth.uid,
                      username: auth.info.name,
                      email:    User.dummy_email(auth),
                      password: Devise.friendly_token[0, 20]
      )
    end
    user.skip_confirmation!
    user.save
    user
省略

こちらのメソッドは下記のコールバックの処理で使用されます。ユーザーが存在する場合としない場合とで条件分岐させてログイン認証の処理を分けていますね。 引数のauthとして渡されるのがrequest.env['omniauth.auth']です。

# app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def github
    @user = User.find_for_github_oauth(request.env["omniauth.auth"], current_user)

    if @user.persisted?
      sign_in_and_redirect @user, :event => :authentication
      set_flash_message(:notice, :success, :kind => "Github") if is_navigational_format?

request.env['omniauth.auth']というリクエストパラメータには、OmniAuthによってHashのデータ構造に似たOmniAuth::AuthHashというクラスのオブジェクトが格納されています。oAuthによるこれらのデータを取得して、検索を行うのですね。

5. dotenv-railsをインストールし、.envファイルを作成して"Client ID"と"Client Secret"を記述

.envのファイルに環境変数としてGitHubAPI keyを登録します。環境変数として認識させるためにdotenv-railsのインストールをお忘れずに。

.envを.gitignoreに置くことでGitHub上へのファイルのコミットを防ぎます。

以上となります。

OmniAuth実装上の注意点

-------deviseでメール認証を実装された方に向けた内容になります-------

実はGitHubの認証が上手くいっても、メール認証の設定によりログインができない場合があるのです。

こちらの記事のコメント欄にも同様の事象を経験されている方がいらっしゃいます。

メール認証のアラートが飛ぶ場合は、GitHub認証時にメール認証を省略するための記述が別途必要なのです。

それが、obj.skip_confirmation!です。

# app/models/user.rb
user = User.create(:username => data.name,
                省略
                )
user.skip_confirmation! #user.saveの前に処理を記述
user.save 

上記の記述をすることで、GitHubによるログインを実行した後にメール認証のアラートが飛ぶことはないはずです。

また処理を分けているので、メール認証も引き続き実行可能です。

ログイン後の画面

GitHub認証後の遷移

f:id:b_leiu:20190517203126p:plain:w400

メール認証後の遷移

f:id:b_leiu:20190517204318p:plain:w400

参考文献

qiita.com

github.com

medium.com

qiita.com

qiita.com

『パーフェクト Ruby on Rails』

最後に

いかがでしたでしょうか。個人的には、OmniAuthの導入そのものより、username追加時のdeviseの処理などが難しく感じました。

次回はActiveStorageについてです!