activeadminのWikiに書いてある通りだと、動作しなかったため、Google認証を導入する手順をまとめてみました。利用したgemは、omniauth-google-oauth2となります。
環境
- Rails 5.2.3
- 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>
おつかれさまでした
これで、Googleアカウントで認証できるようになります。