Rails7でMicrosoft Entra IDを使ったログインを実装する

# Ruby on Rails 7でMicrosoft Entra IDを使ったログインを実装
今回は、Ruby on RailsのDeviseを使って、Microsoft Entra IDでログインできるようにします。
## 前提
### 条件
- Azureアカウントを作成済みである
- Azure Portalへログインできる
### 環境
- ruby 3.3.1
- Rails 7.1.3.4

## Microsoft Entra ID(旧Azure AD)とは？
クラウドベースのID管理とアクセス管理のサービスを提供します。(Microsoft 認定資格試験テキストAZ900:Micosoft Azure Fundamentals 改訂第２版　須屋聡史/富岡洋/佐藤雅信）
今回は、認証･認可サーバをEntra IDに担わせてRails側でその情報を受け取る実装にしていきます。

## プロジェクトの作成
- プロジェクトの作成をします
`$ rails new entraid`(entraid)は適当でOK
- `$ cd entraid`でプロジェクトフォルダに移動します

## Gemの追加
Gemfileに必要なGemを追加します
```ruby:Gemfile
gem 'devise'
gem "omniauth"
gem "omniauth-rails_csrf_protection"
gem 'omniauth-azure-activedirectory-v2'
gem 'dotenv-rails', groups: [:development, :test]
```
- `$ bundle install`を実行します

## Deviseのセットアップ
Deviseをセットアップします

```bash:bash
$ rails generate devise:install
$ rails generate devise User
$ rails db:migrate
```
### Omniauthの設定を追加する
config/initializers/devise.rbファイルに、Azure ADの設定を追加します。
```ruby:config/initializers/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モデルにOmniauthの設定を追加する
app/models/user.rbファイルに以下を追加します。
```ruby:app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:azure_activedirectory_v2]

  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]
      # ユーザーの追加情報を必要に応じて設定
    end
  end
end

```
## コントローラにOmniauthのコールバックを追加する
app/controllers/users/omniauth_callbacks_controller.rbファイルを作成し、以下を追加します。
```ruby:app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  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") if is_navigational_format?
    else
      session["devise.azure_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end

  def failure
    redirect_to root_path
  end
end

```
## ルーティングの設定をする
config/routes.rbファイルに以下を追記します。
```ruby:config/routes.rb
Rails.application.routes.draw do
  devise_for :users, controllers: {
    omniauth_callbacks: 'users/omniauth_callbacks'
  }

  # 他のルート
  # ルートパスの設定
  root to: 'home#index'
end

```
## ホームページの作成
ホームページのコントローラとアクションを作成します。
```bash:bash
$ rails generate controller home index
```
これで、app/controllers/home_controller.rbとapp/views/home/index.html.erbが作成されます。

## ビューをカスタマイズする
ログインボタンを追加するために、ビューをカスタマイズします。例えば、app/views/devise/sessions/new.html.erbに以下を追加します。

```ruby:app/views/devise/sessions/new.html.erb
<h2>Log in</h2>
<%= render "devise/shared/links" %>
```

## Azureポータルでアプリケーションを登録する
1. Azureポータルにサインインし、「Azure Entra ID」に移動します。
![EntraID1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/6510c7f2-2b0d-a0c8-323c-e5647757d787.png)

1. 「アプリの登録」をクリックし、新しい登録を作成します。
![EntraID2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/eb2bef6d-e5ef-0953-936b-715dfec36a1b.png)
1. 新規登録をクリックします
![EntraID3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/2b17f44d-c226-a143-f93b-c8477d311653.png)
1. 必要な情報を入力し、リダイレクトURIとしてhttp://localhost:3000/users/auth/azure_activedirectory_v2/callbackを追加します。
![EntraID4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/3ee39074-77c3-f0cd-9924-5adb2a4cc15d.png)


1. 「証明書とシークレット」セクションで、新しいクライアントシークレットを作成します。このシークレットは後で使います。
![EntraID5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/3c06cab8-01a6-28f7-f110-e909bfa81fa5.png)
![EntraID6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/0ea3546a-2585-3e8f-6518-b35fca295c05.png)
![EntraID7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/0b99c6ff-be9b-9c11-fe47-75a3a281525c.png)
![EntraID8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/5b21541a-e414-928c-2d45-4fe1a4b9be4e.png)
1. .envファイルを作成します。
AZURE_CLIENT_ID,AZURE_TENANT_IDは、以下の画像の欄からコピーします。
AZURE_CLIENT_SEACRETは手順５で取得したシークレット値を利用します。
![EntraID9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/8ec8f4b6-fb2a-e71e-8424-4596834acff1.png)
```env:.env
AZURE_CLIENT_ID=your_client_id
AZURE_CLIENT_SECRET=your_client_secret
AZURE_TENANT_ID=your_tenant_id
```
7.Railsを再起動します。
```bash:bash
$ rails s
```