BETA

Omniauthを使ってGithub認証を実装する

投稿日:2019-12-21
最終更新:2020-01-12

前回の記事の続きです。
今回はOmniauthを使ってGithub認証の実装方法を説明していきます。

また、メール認証でもGithub認証でもどちらでもログインできるようにします。

GitHubで必要な情報を取得

まずはGithubでOmniauthを使うために必要な情報を取得します。

自分のGtihubアカウントにログインして、「Setting」→「Developer Settings」→「New Oauth APP」にアクセスしてください。
そして以下のように項目を入力します。

  • Application name: アプリケーション名-deveopment
  • Homepage URL: http://localhost:3000/
  • Authorization callback URL: http://localhost:3000/users/auth/github/callback

終わったら、「Register application」をクリックします。
「Client ID」と「Client Secret」が発行されますので、それをメモっておいてください。

環境変数の設定

direnvインストール

プロジェクトごとに環境変数を設定できるdirenvをインストールします。
direnvで環境変数などを個別に設定 (rails)

Homebrewでインストールします。

$ brew install direnv  

direnvの設定を~/.zshrcに記述していきます。
bashを使っている方は~/.bash_profileまたは~/.bashrcに記述してください。

~/.zshrcに追記

# direnv(.envrc)用設定  
export EDITOR=vim  
eval "$(direnv hook zsh)"  

終わったら反映させます。

$ source ~/.zshrc  

次にプロジェクトディレクトリ内に移動して、以下のコマンドを実行します。
すると、.envrcという環境変数を記述しておくファイルが作成されます。

$ direnv edit .  

.envrcにさっきメモしておいた「Client ID」と「Client Secret」を記述します。
.envrc

export GITHUB_ID=メモした"Client ID"  
export GITHUB_SECRET=メモした"Client Secret”  

最後に、.envrcは機密情報のためGithubリポジトリに含めてはいけないので、.gitignoreに以下を追記しておきます。

$ echo '/.envrc' >> .gitignore  

これで、一通り準備は完了しました。

これから、Github認証の方を実装していきます。

Omiauthインストール

Gemfileに以下を記述。

gem 'omniauth-github'  

インストール。

$ bundle  

マイグレーションファイル作成

deviseモデルのUserに、Omniauthの認証で使うuidカラムとproviderカラムを追加していきます。

$ rails g migration AddColumnsToUsers uid:string provider:string  

今回はそれぞれに

  • NULL値は許可しない
  • デフォルトあり

を設定します。

また、uidproviderの組み合わせが一意になることを保証するためにインデックスをつけておきます。

db/migrate/***_add_omniauth_columns_to_users.rb

class AddOmniauthColumnsToUsers < ActiveRecord::Migration[6.0]  
  def change  
    add_column :users, :uid, :string, null: false, default: ''  
    add_column :users, :provider, :string, null: false, default: ''  

    add_index :users, [:uid, :provider], unique: true  
  end  
end  

終わったら忘れず、マイグレートしておきましょう。

$ rails db:migrate  

Deviseの設定

deviseの設定ファイルにさっき環境変数に設定したGithubの情報を記述します。

config/initializers/devise.rb

Devise.setup do |config|  

  ~省略~  

  config.omniauth :github, ENV['GITHUB_ID'], ENV['GITHUB_SECRET'], scope: 'user,public_repo'  

  ~省略~  

end  

これでGithubでのOmniauth認証が使えるようになりました。

Userモデルにモジュールを追加

UserモデルにOmniauthモジュールを追加して、Github認証を有効にします。

app/models/user.rb

devise :database_authenticatable, :registerable,  
       :recoverable, :rememberable, :trackable, :validatable,  
       :confirmable, :omniauthable, omniauth_providers: %i[github]  

Userモデルにfindメソッドを実装

以下のように記述します。

app/models/user.rb

def self.find_for_github_oauth(auth, signed_in_resource = nil)  
  where(provider: auth.provider, uid: auth.uid).first_or_create! do |user|  
    user.username = auto.info.name  
    user.email = User.dummy_email(auth)  
    user.password = Devise.friendly_token[0, 20]  

    # メール認証をスキップする  
    user.skip_confirmation!  
  end  
end  

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

メール認証の時に必ずメールアドレスが必要になるので、一意なuidproviderの組み合わせを利用することで、一意なメールアドレスを作成しています。

通常新規登録時の uidフィールド設定の実装

uidproviderはNULL値が許可されず、組み合わせも一意でなければいけないので、uidもしくはproviderを必ず埋めなければなりません。
今回はuidを必ず埋めることにします。

まずはUserモデルにランダムな文字列を返すメソッドを定義します。
これがuidに入る予定です。

app/models/user.rb

def self.create_unique_string  
  SecureRandom.uuid  
end  

deviseは新規登録時にapp/devise/registrations_controller.rbを用いるのでそれを継承したコントローラを作成し、そこでさっきのメソッドを呼び出します。
以下を記述してください。

app/controllers/users/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController  
  def build_resource(hash = {})  
    hash[:uid] = User.create_unique_string  
    super  
  end  
end  

これで新規登録時に必ずuidが埋まるようになりました。

最終的なapp/models/user.rbは以下のようになります。

devise :database_authenticatable, :registerable,  
       :recoverable, :rememberable, :trackable, :validatable,  
       :confirmable, :omniauthable, omniauth_providers: %i[github]  

  ~略~  

def self.find_for_github_oauth(auth, signed_in_resource = nil)  
  where(provider: auth.provider, uid: auth.uid).first_or_create! do |user|  
    user.username = auto.info.name  
    user.email = User.dummy_email(auth)  
    user.password = Devise.friendly_token[0, 20]  


    # メール認証をスキップする  
    user.skip_confirmation!  
  end  
end  

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

def self.create_unique_string  
  SecureRandom.uuid  
end  

Userコントローラにコールバック処理を実装

公式ドキュメント通りにコールバック処理を記述していきます。

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?  
    else  
      session['devise.github_data'] = request.env['omniauth.auth']  
      redirect_to new_user_registration_url  
    end  
  end  

  def failure  
    redirect_to root_path  
  end  
end  

ルーティング

ルーティングを設定していきます。
i18nでの日本語化をサブディレクトリで行っている場合、多少工夫が必要です。
自分はサブディレクトリ方式で行っていたので、以下の記事を参考に設定しました。
How-To:-OmniAuth-inside-localized-scope

具体的にはコールバック処理の部分だけi18nスコープの外側に記述してあげることでなんとかできました。
また新規登録時に使うコントローラーはちゃんとさっき作成したapp/controllers/users/registrations_controller.rbを記述しておきましょう。

config/routes.rb

devise_for :users, only: :omniauth_callbacks, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }  

scope '(:locale)', locale: /#{I18n.available_locales.map(&:to_s).join('|')}/ do  
  devise_scope :user do  
    root to: 'devise/sessions#new'  
  end  

  devise_for :users, skip: :omniauth_callbacks, controllers: {  
    registrations: 'users/registrations',  
  }  
end  

Viewでリンクを出力

最後にビューでリンクを用意しましょう。

omniauth認証を有効にすると、user_{provider}_omniauth_authorize_pathというヘルパーメソッドが使用できるようになります。
githubの場合はuser_github_omniauth_authorize_pathになります。

以下のように記述することで、リンクを出力できます。

<%= link_to 'Githubでログイン', user_github_omniauth_authorize_path %>  

これでおしまいです!
お疲れ様でした!!

今回できるようになったこと

  • メールアドレスとパスワードで認証して新規登録&ログインできる
  • ユーザーにメールを送信してリンクをクリックすることでアカウントを有効化する
  • Githubのアカウントだけで新規登録&ログインできる

以上3点が実装できました。

次はTwitterでの認証やFacebookでの認証なども実装していきたいですね。
また今度挑戦してみようと思います!

参考にしたサイト等

OmniAuth: Overview
direnvで環境変数などを個別に設定 (rails)
Rails5.1でGithubログインを実装する
RailsでDeviseとOmniAuthによるTwitter/FacebookのOAuth認証、および通常フォーム認証を併用して実装

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

BЯunoの技術ブログ。日々学んだことを記録していくよ。

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう