やりたいこと
-
deviseのomniauthableの機能でgithubログインを実装する
-
挙動
- サインアップ、ログイン画面より「GitHub認証」のボタンを押下
- GitHubのログイン画面へ遷移しid,パスを入力しログインボタンを押下
- github上で認証するためのトークンを発行し、それをWebサイト側で検証
- 上記が認証されるとトップ画面へ遷移する。
調査
- 必要なこと
- omniauthableの実装に必要なgemをインストールする。
- GitHubにてOAuthアプリを作成する。
- 上記で生成されたCLIENT_IDとSECRET_PASSをenvファイルへ記述
- controllerにて上記認証情報の処理を記述(むずい)
- モデルのメソッドにて上記paramsをuserテーブルへの保存するためのメソッドを記述
- User modelに
:omniauthable
を追加 - viewの実装を行う
実際にやったこと
ライブラリ関連
- Gemfileに以下を記述→bundle install
gem 'omniauth'
gem 'omniauth-github'
gem 'omniauth-rails_csrf_protection'
group :development, :test do
gem 'dotenv-rails'
end
[Rails]deviseとomniauthによるgithubログイン
OAuthのID,パス生成
- https://github.com/settings/developers よりOAuthアプリを作成(Homepage URL:http://localhost:3000/, URL:http://localhost:3000/auth/github/callback)
【2021年4月現在】GitHubのClient IDとClient secretsを取得する手順 - No day younger than today
- OAuthのアプリケーション設定より「Client ID」と「Client secret」のidをそれぞれ取得し、環境変数として.envへ記述。
#上記にて自分で設定したkeyを設定
GITHUB_ID = '*********'
GITHUB_SECRET = '********'
- 記述した.envファイルは外部に漏れないように
gitignore
ファイルに記述
# Ignore env File
/.env
-
/initializers
に上記ENVファイルにて設定した環境変数を記述し読み込めるようにする
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
config.omniauth :github, ENV['GITHUB_ID'], ENV['GITHUB_SECRET'], scope: 'user,public_repo'
DB関連
-
rails g migration AddOmniauthToUsers
にてmigrationファイルを生成 - →以下記述し、
rails db:migrate
class AddOmniauthToUsers < ActiveRecord::Migration[7.0]
def change
add_column :users, :uid, :string
add_column :users, :provider, :string, null: false, default: ""
add_index :users, %i[uid provider], unique: true
end
end
-
app/models/user.rb
に,omniauthable
モジュールと、validationを記述
# frozen_string_literal: true
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
validates :name, presence: { message: "can't blank" }
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable, :lockable, :timeoutable, :trackable,:omniauthable, omniauth_providers: %i[github]
#追加
validates :birth_day, presence: { message: "can't blank" }
validates :tel_number, presence: { message: "can't blank" }
#追加
validates :uid, uniqueness: { scope: :provider }, if: -> { uid.present? }
end
routeの設定
Rails.application.routes.draw do
〜略
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks'}
end
controllerの設定
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token, only: :github
def github
@user = User.from_omniauth(request.env['omniauth.auth'])
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: "Github") if is_navigational_format?
else
session["divise.github_data"] = request.env["omniauth.auth"].except(:extra)
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end
user.rbモデルにメソッド設定
# frozen_string_literal: true
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
validates :name, presence: { message: "can't blank" }
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable, :lockable, :timeoutable, :trackable,:omniauthable, omniauth_providers: %i[github]
validates :birth_day, presence: { message: "can't blank" }
validates :tel_number, presence: { message: "can't blank" }
validates :uid, uniqueness: { scope: :provider }, if: -> { uid.present? }
#追記
def self.form_omniauth(auth)
where(uid: auth.uid, provider: auth.provider).first_or_create! do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.name = auth.info.name
user.birth_day = Date.parse('1993-04-21')
user.tel_number = '12345678'.to_i
end
end
end
- first_or_createについて
覚えておくと幸せになれるActiveRecord::Relationメソッド6選 - Qiita
viewの設定
-
app/views/shared/_link.html.slim
のomniauthボタンのroutingの変更
#〜省略
- if devise_mapping.omniauthable?
- resource_class.omniauth_providers.each do |provider| #変更
= button_to " #{OmniAuth::Utils.camelize(provider)}で続ける", user_github_omniauth_authorize_path(resource_name, provider), data: { turbo: false } ,class: "btn btn-primary"
br
- Githubログイン用のボタンがサインアップ画面とログイン画面に表示される
結果
- 「Githubで続ける」を押下してログインしようと試みると
Not found. Authentication passthru.
とエラーが表示されて認証が通らなかった。
原因究明と解決
-
passthru
は聞きなれない単語だがpassthrough
(=通過する、素通りする)と同じ意味
- ログを確認すると認証用パラメータは生成されているように見える。
- つまり生成された認証paramasが入力→出力へ「内部で何もせず素通り(pass through)」しているということ? 正しくparamsが送られてない?
- deviseの公式ドキュメントを確認すると、ボタンのmethodにpostを指定するように記述されていた。ただ、button_to場合は必要なく、link_toの場合は
method: :post
の追記が必要 -
button_to
を用いて下記設定したが解消されず。
- if devise_mapping.omniauthable?
- resource_class.omniauth_providers.each do |provider|
= button_to " #{OmniAuth::Utils.camelize(provider)}で続ける", user_github_omniauth_authorize_path ,class: "btn btn-primary"
br
-
config/initializers
直下にomniauth.rb
を作成し、以下記述
Rails.application.config.middleware.use OmniAuth::Builder do
OmniAuth.config.allowed_request_methods = [:post, :get]
end
→これによりpostとgetメソッドが許可されるので、送られてきた認証paramasが素通りせず、受け取られるはず
- サインアップ画面が表示されたのでid,passを入力すると、、、
- 今度はrouting errorが表示された。エラー画面では
/auth/github/callback
のrouteがないと怒られている。
- 改めて
config/route
を確認すると,omniauth_callbacks: 'users/omniauth_callbacks'
と設定しているので、callbackの接続するパスはusers/auth/github/callback
となるはず。
Rails.application.routes.draw do
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks'}
end
- https://github.com/settings/developers のAuthorizeのcallback URLを見るとusersがないので改めて http://localhost:3000/users/auth/github/callback と設定
- 今度は認証画面に遷移することができた。Authorizeをクリックすると無事にログインすることができた!!
参考