Laravel Socialite を使って Entra ID で SSO できるようにする(実装編)
前回の記事を書いてから半年以上が経ってしまいましたが、Laravel Socialite を使って Entra ID で SSO できるようにするの Laravel 側の実装編です。
基本的には https://socialiteproviders.com/Saml2/ の説明に沿って進めていきます。
Saml2 Service Provider のインストール
composer require socialiteproviders/saml2
設定ファイルの編集
config/services.php に必要な設定を追加しますが、Entra ID の場合、実際に必要なのは以下の2項目だけです。
    'saml2' => [
        'metadata' => '(準備編で取得した「アプリのフェデレーションメタデータURL」)', // IdPのMetadata
        'sp_default_binding_method' => \LightSaml\SamlConstants::BINDING_SAML2_HTTP_POST,
    ],
サービスプロバイダの登録
bootstrap/providers.php に \SocialiteProviders\Manager\ServiceProvider::class を追加します。他にサービスプロバイダを追加していなければ、bootstrap/providers.php はこんな感じになるはずです。
<?php
return [
    App\Providers\AppServiceProvider::class,
    \SocialiteProviders\Manager\ServiceProvider::class,
];
イベントリスナの追加
app/Providers/AppServiceProvider.php の boot メソッドにイベントリスナを追加します。
public function boot(): void
{
    Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
        $event->extendSocialite('saml2', \SocialiteProviders\Saml2\Provider::class);
    });
}
ルートの追加
上記までで準備ができたので、routes/web.php に認証に必要なルートを追加します。
Route::get('/auth/redirect', function () {
    return Socialite::driver('saml2')->redirect();
})->name('saml2.login');
Route::post('/auth/callback', function () {
    $entraUser = Socialite::driver('saml2')->stateless()->user();
    // Entra で認証済みのユーザー情報でユーザーインスタンスを作成・更新
    $user = User::updateOrCreate([
        'entra_id' => $entraUser->id,
    ], [
        'name' => $entraUser->last_name . ' ' . $entraUser->first_name,
        'email' => $entraUser->email,
    ]);
    Auth::login($user);
    return redirect()->route('home');
});
/auth/redirect へのリンクをクリックすると、Microsoft アカウントへのログイン画面が表示されます。認証後、/auth/callback に戻ってくるので、取得したユーザー情報を使ってユーザーインスタンスを作成・更新し、Auth::login メソッドに渡して認証しています。
CSRF エラー対応
上記までの作業を行ってテストを行うと、CSRF のエラーが発生します。Entra から戻ってくる /auth/callback の POST リクエストに CSRF トークンが含まれていないからです。そこで、bootstrap/app.php に下記を追加して、CSRF のチェックを無効にします。
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->validateCsrfTokens(except: [
            'auth/callback',
        ]);
    })
まとめてみると、比較的簡単に SAML によるシングルサインオンが実装できるのですが、修正するファイルがあちこちに散らばっているので、修正漏れ→動かないとなりがちです。そんなときにこの記事を思い出していただければと思います。





ディスカッション
コメント一覧
まだ、コメントがありません