Table of Contents
やりたいこと
認証画面で「Azure ADで認証」を選択できるようにします。
通常のID/PASS認証を実装
まずはdeviseを使って普通にID/PASS認証を実装します。 既にご存知の方は読み飛ばしても大丈夫です。
rails new
まずはrains newします。 DBはPostgreSQLとしていますが、他のDBでも問題ありません。
# Railsアプリを作成
$ rails new devise_omniauth_azure_ad -d postgresql
$ cd devise_omniauth_azure_ad
# DB接続を確認
$ vi config/database.yml # 適宜編集
$ bin/rails db:create rails db:migrate
Deviseの導入
以下コマンドを実行してdeviseをインストールします。
$ bundle add devise
$ bin/rails g devise:install
インストール後、セットアップ手順が表示されるのでそれぞれ実施します。
default_url_options
に localhost:3000
を追加します。
config/environments/development.rb
require "active_support/core_ext/integer/time"
Rails.application.configure do
# 省略
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end
ルーティングに root
を追加。
config/routes.rb
Rails.application.routes.draw do
root to: 'home#index'
end
root
に相当するController, VIEWを作成。
$ bin/rails g controller home index
home#index
へのアクセスを認証必須にする。
app/controllers/home_controller.rb
class HomeController < ApplicationController
before_action :authenticate_user!
def index
end
end
Flashメッセージが表示されるようHTMLを修正。
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>DeviseOmniauthAzureAd</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
<%= yield %>
</body>
</html>
deviseのVIEWファイルを作成。
$ bin/rails g devise:views
Userモデルの作成
以下コマンドを実行して、Userモデルを作成します。
$ bin/rails g devise user
モデルを作成したらマイグレーションも実行しておきましょう。
$ bin/rails db:migrate
動作確認
予めRails Consoleにてダミーユーザーを作成します。
$ bin/rails c
irb(main):001:0> User.create(email: 'test@example.com', password: 'password1!', password_confirmation: 'password1!')
Railsサーバーを起動し、ブラウザで http://localhost:3000 へアクセスします。
$ bin/rails s
以下のようにログインページへリダイレクトされます。 ID, Passwordを入力して「Log in」をクリックしましょう。
ログインに成功しました。
Azure ADと認証を連携させる
ここからがAzure ADと認証を連携させる手順です。 手順はdeviseのWikiにも記載されているので、迷ったらこちらも併せて参照ください。
Gemを追加する
以下コマンドを実行して必要なGemをインストールします。
$ bundle add omniauth -v 1.9.1
$ bundle add omniauth-azure-activedirectory-v2
$ bundle add dotenv-rails
2021-4-20現在、omniauth
の最新バージョンをインストールするとRailsの起動時に次のようなエラーが発生します。
$ bin/rails c
/devise_omniauth_azure_ad/vendor/bundle/ruby/3.0.0/gems/devise-4.7.3/lib/devise/omniauth.rb:12:in `<main>': You are using an old OmniAuth version, please ensure you have 1.0.0.pr2 version or later installed. (RuntimeError)
このため、下記Issueが解決するまでは上記のように 1.9.1
をインストールするようにしましょう。
認証プロバイダを追加
config/initializers/devise.rb
に以下のように追記することで認証プロバイダを追加します。
config/initizlizers/devise.rb
Devise.setup do |config|
# 省略
config.omniauth :azure_activedirectory_v2,
client_id: ENV['AZURE_CLIENT_ID'],
client_secret: ENV['AZURE_CLIENT_SECRET'],
tenant_id: ENV['AZURE_TENANT_ID']
end
Userモデルの認証設定を追加
OAuth2認証に対応するため、認証設定を追加します。
app/models/user.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:omniauthable, omniauth_providers: [:azure_activedirectory_v2]
end
また、この後追加するコントローラから使用するメソッドを追加します。
app/models/user.rb
class User < ApplicationRecord
# 省略
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0, 20]
# MEMO: 氏名やアバター画像等を取得したい場合は有効化する
# user.name = auth.info.name
# user.image = auth.info.image
end
end
end
OAuthで使用するカラムが増えるので、追加します。
$ bin/rails g migration AddColumnsToUsers uid:string provider:string
以下のようにマイグレーションファイルを編集します。
db/migrate/xxxxxxxxxxxxxx_add_columns_to_users.rb
class AddColumnsToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :uid, :string, null: false
add_column :users, :provider, :string, null: false, default: ""
add_index :users, [:uid, :provider], unique: true
end
end
カラムを追加した都合上、既にユーザーが存在しているとマイグレーションエラーとなるため、以下のようにリセット→マイグレーションを実行します。
$ bin/rails db:migrate:reset
OAuth2コールバック用のコントローラを追加
OAuth2認証におけるコールバックを処理するコントローラを追加します。
$ mkdir app/controllers/users
$ touch app/controllers/users/omniauth_callbacks_controller.rb
次のように実装します。
app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token, only: :azure_activedirectory_v2
def azure_activedirectory_v2
@user = User.from_omniauth(request.env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: "azure_activedirectory_v2") if is_navigational_format?
else
session["devise.azure_activedirectory_v2_data"] = request.env["omniauth.auth"].except(:extra)
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end
OAuth2コールバック用のroutesを追加
config/routes.rb
を次のように修正します。
config/routes.rb
Rails.application.routes.draw do
root to: 'home#index'
devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }
end
Azure ADの設定
Azure Portalにログインし、Azure Active Directory→App registrationsへ移動します。
「+ New registration」をクリックしましょう。
NameおよびRedirect URIを入力します。Redirect URIは http://localhost:3000/users/auth/azure_activedirectory_v2/callback とします。
アプリケーションの登録が完了したら、Client IDおよびTenant IDが表示されるので控えておきます。(後ほど使用します)
「Certificates & secrets」→「+ New client secret」の順でクリックします。
説明と期限を入力して、「Add」をクリックします。
作成が完了するとClient Secretが表示されるので控えておきます。(後ほど使用します)
Railsのルートディレクトリに .env
を作成し、Client ID, Tenant ID, Client Secretを記載します。
.env
AZURE_CLIENT_ID=xxxx
AZURE_CLIENT_SECRET=xxxx
AZURE_TENANT_ID=xxxx
このファイルは秘匿情報ですので、.gitignore
に追記しておきます。
$ echo '.env' >> .gitignore
動作確認
Railsサーバーを起動し、ブラウザで http://localhost:3000 へアクセスします。
$ bin/rails s
以下のようにログインページへリダイレクトされます。 「Sign in with AzureActivedirectoryV2」をクリックしましょう。
Microsoftのログイン画面が表示されます。使用するテナントに属するアカウントを選択しログインしましょう。
アクセス許可する内容を確認し「承諾」をクリックします。
ログイン成功しました。
まとめ
いくつかハマりどころはありますが、公式のドキュメントの手順をAzure用にカスタマイズすることで、OAuth2認証を実現できました。
Azureと密接に連携したサービスを実装する際、ぜひお試しください。