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

activeadminにおけるGoogle認証(omniauth-google-oauth2)導入手順

More than 3 years have passed since last update.

activeadminWikiに書いてある通りだと、動作しなかったため、Google認証を導入する手順をまとめてみました。利用したgemは、omniauth-google-oauth2となります。

環境

  • Rails 4.2.6
  • activeadmin 1.0.0.pre4
  • devise 4.2.0

導入手順

※ rails new..activeadminのインストール手順等は省略します。

1. omniauth-google-oauth2 をGemfileに追加して bundle

2. AdminUserに :omniauthable モジュールを有効化

app/models/admin_user.rb
class AdminUser < ActiveRecord::Base
  # パスワードでの認証を廃止するため :recoverable, :rememberable は削除(共用させる場合は残す)
  devise :database_authenticatable, :omniauthable, :trackable, :validatable
end

3. devise に omniauth の設定を追加

config/initializers/devise.rb
config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'], scope: "email"

4. dotenv-rails をGemfileに追加して bundle

Gemfile
gem 'dotenv-rails', require: 'dotenv/rails-now'

5. .env に 必要な環境変数を設定

.env
GOOGLE_CLIENT_ID=**********YOUR_CLIENT_ID**********
GOOGLE_CLIENT_SECRET=**********GOOGLE_CLIENT_SECRET**********

クライアントIDとクライアントシークレットの設定手順は、こちらに書いてある通りです。

ただし、リダイレクトURIは http://127.0.0.1:3000/admin/auth/google_oauth2/callbackに設定する必要があります(localhostだと正しくリダイレクトされませんのでご注意ください)

6. マイグレーションの作成と実行

$ bundle exec rails g migration change_columns_in_admin_users
db/migrate/YYYYMMDDHHMMSS_change_columns_in_admin_users.rb
class ChangeColumnsInAdminUsers < ActiveRecord::Migration
  def change
    add_column :admin_users, :provider, :string
    add_column :admin_users, :uid,      :string

    add_index :admin_users, [:provider, :uid], unique: true

    # パスワード認証を廃止するため、以下は削除(共存させる場合は残す)
    remove_column :admin_users, :reset_password_token,   :string
    remove_column :admin_users, :reset_password_sent_at, :datetime
    remove_column :admin_users, :remember_sent_at,       :datetime
  end
end
$ bundle exec rake db:migrate

7. AdminUserにAuthHashに対応するメソッドを追加

app/models/admin_user.rb
class AdminUser < ActiveRecord::Base

  devise :database_authenticatable, :omniauthable, :trackable, :validatable

  with_options presence: true do
    validates :email # whitelistでフィルタする場合、inclusionやformatのvalidationを追加
    validates :provider
    validates :uid, uniqueness: { scope: :provider }
  end

  # こちらは、ほぼ公式wiki通りに書いているが、パスワード認証しないなら、常時falseでよい
  # Devise override to ignore the password requirement if the user is authenticated
  def password_required?
    return false if provider.present?
    super
  end

  class << self
    def from_omniauth(auth)
      admin_user = where(email: auth.info.email).first || where(auth.slice(:provider, :uid).to_h).first || new
      admin_user.tap { |this| this.update_attributes(provider: auth.provider, uid: auth.uid, email: auth.info.email) }
    end
  end
end

8. コールバックを受けるコントローラの実装

app/controllers/admin_users/omniauth_callbacks_controller.rb
class AdminUsers::OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def all
    admin_user = AdminUser.from_omniauth(auth_hash)

    if admin_user.persisted?
      flash.notice = "Signed in!"
      sign_in_and_redirect admin_user
    else
      flash.notice = "We couldn't sign you in because: " + admin_user.errors.full_messages.to_sentence
      redirect_to new_admin_user_session_url
    end
  end

  # providerを追加したら、aliasも追加
  # 追加予定ないなら、#all => #google_oauth2 に変更する感じ
  alias_method :google_oauth2, :all

  private

  def auth_hash
    request.env["omniauth.auth"]
  end
end

9. ルーティングでomniauth_callbacksの際に、利用するコントローラをassign

config/routes.rb
Rails.application.routes.draw do
  devise_config = ActiveAdmin::Devise.config
  devise_config[:controllers][:omniauth_callbacks] = 'admin_users/omniauth_callbacks'
  devise_for :admin_users, devise_config
  ActiveAdmin.routes(self)
  #...

10. ログインフォームからパスワードフォームを撤去

テンプレートは、activeadminの元ファイルから拝借

app/views/active_admin/devise/sessions/new.html.erb
<div id="login">
  <h2><%= render_or_call_method_or_proc_on(self, active_admin_application.site_title) %> <%= title t('active_admin.devise.login.title') %></h2>
  <div style="text-align: center">
    <%- if devise_mapping.omniauthable? %>
      <%- resource_class.omniauth_providers.each do |provider| %>
        <%= button_to(
              t('active_admin.devise.links.sign_in_with_omniauth_provider', provider: provider.to_s.titleize),
              omniauth_authorize_path(resource_name, provider)) %><br />
      <% end -%>
    <% end -%>
  </div>
</div>

:older_man: おつかれさまでした :older_man:

これで、Googleアカウントで認証できるようになります。

認証前

認証後

なお、以下が当記事のサンプルアプリケーションとなります。

参考

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