LaravelでKeycloakを用いてSSOを実現する
以下のように、KeycloakとLaravelとを別のPCで構築し、SSOで連携の上で、Laravel側でログインユーザの属性(カスタム属性を含む)情報を取得するまでの動作を確認した。この記事ではKeycloak側の構築手順も記載しているが、主となるのはLaravel側の手順となる。
- Keycloak
- Windows10
- WSL2
- Laravel
- Windows11
- WSL2
Keycloak設定
以下Keycloak用のPCでの作業となる。
ダウンロードと起動
以下に記述があるようにWSL2上でKeycloakコンテナを開始する。執筆時点で最新は25.0.2であった。docker desktopでも同様のことはできると思うが、使ったことがないのでわからない。
docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:25.0.2 start-dev
コンテナを停止してもデータを残したい(永続化する)ならば、例えば以下のようにvolumeを指定して、Keycloakコンテナを開始する。
docker run -v keycloak:/opt/keycloak/data -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:25.0.2 start-dev
以下のようなメッセージがでたら起動している。
2024-08-19 05:59:47,197 WARN [org.keycloak.quarkus.runtime.KeycloakMain] (main) Running the server in development mode. DO NOT use this configuration in production.
admin ログイン
ブラウザで http://localhost:8080 にアクセスする。
Username or email
/Password
にadmin
/admin
をセットしてSign in
する。
ログイン(Sign in)できた。
realm作成
ナビゲーションメニューのKeycloak
ドロップリストを展開してCreate Realm
ボタンをクリックする。ちなみにRealmはレルムと読むらしい。
Create realm画面に遷移する。Realm name
テキストボックスにmyrealm
と入力しCreate
ボタンをクリックする。
realm設定の変更
ナビゲーションメニューの Realm settings
項目をクリックしてrealm settings画面を開く。
User profile
ページ内のタブ上の<
, >
ボタンを使ってUser profile
タブを探し、選択する。
user_address
Create attribute
ボタンをクリックして、Create attribute画面を表示する。
以下のように項目をセットしCreate
ボタンをクリックする。
-
Attribute [Name]:
user_address -
Display name:
${user_address} -
Multivalued:
Off -
Attribute group:
None -
Enabled when:
Always -
Required field:
Off -
Permission Who can edit?
User:
Off,Admin:
On -
Permission Who can view?
User:
On,Admin:
On
gender_code
前項と同様にCreate attribute
ボタンをクリックして、Create attribute画面を表示する。
以下のように項目をセットしCreate
ボタンをクリックする。
-
Attribute [Name]:
gender_code -
Display name:
${gender_code} -
Multivalued:
Off -
Attribute group:
None -
Enabled when:
Always -
Required field:
Off -
Permission Who can edit?
User:
Off,Admin:
On -
Permission Who can view?
User:
On,Admin:
On
birth_date
前項と同様にCreate attribute
ボタンをクリックして、Create attribute画面を表示する。
以下のように項目をセットしCreate
ボタンをクリックする。
-
Attribute [Name]:
birth_date -
Display name:
${birth_date} -
Multivalued:
Off -
Attribute group:
None -
Enabled when:
Always -
Required field:
Off -
Permission Who can edit?
User:
Off,Admin:
On -
Permission Who can view?
User:
On,Admin:
On
Client作成
ナビゲーションメニューのClients
要素をクリックする。
Clients画面に遷移する。
Create client
ボタンをクリックして、Create client画面General Settingsページに遷移する。
Client ID
テキストボックスに「sample-client」と入力してNext
ボタンをクリックする。Capability configページに遷移する。
-
Client authentication:
On -
Standard flow:
On -
Direct access grants:
Off
としてNext
ボタンをクリックする。Login settingsページに遷移する。
Valid redirect URIs
テキストボックスおよびWeb origins
にも「*」と入力しSave
ボタンをクリックする。Client details(sample-client)画面に遷移する。
Credentialの確認
Client details(sample-client)画面で、Credential
タブを選択しタブ内容を表示する。
Client Authenticator
が、「Client id and Secret」であることを確認するとともに、Client Secret
の値を別途保存しておく。
なお、ここで設定した sample-client
が後に使うKEYCLOAK_CLIENT_ID
で、取得したClient secret
がKEYCLOAK_CLIENT_SECRET
となる。
mapperを構成
Client details(sample-client)画面で、Client scopes
タブを選択すると、client scopeの一覧を表示する。
sample-client-dedicated
をクリックして、sample-client-dedicatedスコープのMapper一覧画面を表示する。
user_address
Configure a new mapper
ボタンをクリックして、mapper構成ダイアログを表示する。
User Attribute
マッパーを選択して、mapper追加画面を表示し以下のように入力する。Save
ボタンで保存する。
-
Name:
user_address -
User Attribute:
user_address(ドロップリストから選択) -
Token Claim Name:
user_address -
Claim JSON Type:
String -
Add to ID token:
On -
Add to Access token:
On -
Add to lightweight access token:
Off -
Add to userinfo:
On -
Add to token introspection:
On -
Multivalued:
Off -
Aggregate attribute values:
Off
Save後、画面上部のパンくずリスト(Clients
> Client details
> Dedicated scopes
> Mapper details
)のDedicated scopes
リンクをクリックして、dedicated scopes(sample-client-dedicated)のMapper一覧画面を表示する。
gender_code
dedicated scopes(sample-client-dedicated)のMapper一覧画面で、Add mapper
ドロップリストからBy configuration
を選択したのち、前節と同様に、User Attribute
マッパーを選択し、mapper追加画面で以下のように入力した後に、Save
ボタンで保存する。
-
Name:
gender_code -
User Attribute:
gender_code(ドロップリストから選択) -
Token Claim Name:
gender_code -
Claim JSON Type:
String -
Add to ID token:
On -
Add to Access token:
On -
Add to lightweight access token:
Off -
Add to userinfo:
On -
Add to token introspection:
On -
Multivalued:
Off -
Aggregate attribute values:
Off
Save後、画面上部のパンくずリスト(Clients
> Client details
> Dedicated scopes
> Mapper details
)のDedicated scopes
リンクをクリックし、dedicated scopes(sample-client-dedicated)のMapper一覧画面を表示する。
birth_date
dedicated scopes(sample-client-dedicated)のMapper一覧画面で、Add mapper
ドロップリストからBy configuration
を選択したのち、前節と同様に、User Attribute
マッパーを選択し、mapper追加画面で以下のように入力した後に、Save
ボタンで保存する。
-
Name:
birth_date -
User Attribute:
birth_date(ドロップリストから選択) -
Token Claim Name:
birth_date -
Claim JSON Type:
String -
Add to ID token:
On -
Add to Access token:
On -
Add to lightweight access token:
Off -
Add to userinfo:
On -
Add to token introspection:
On -
Multivalued:
Off -
Aggregate attribute values:
Off
User作成
ナビゲーションメニューのUsers
項目をクリックする。
Users画面に遷移する。
Create new user
ボタンをクリックしてCreate user画面に遷移する。例えば以下のように項目を入力する。
-
Required user actions:
(空欄) -
Email verified:
On -
Username:
test000 -
Email:
test000@example.com -
First name:
t000 -
Last name:
test000 -
user_address:
札幌市中央区北1条西3丁目3番地 敷島北一条ビル6階 -
gender_code:
0 -
birth_date:
2002-04-15
Create
をクリックして、User details画面に遷移する。
次に、User details画面のCredentials
タブをクリックしてパスワードを追加する。ここでは、Temporary
スイッチはOffにしておく。
Save
ボタンをクリックすると確認ダイアログが出現するので、Save password
を選択する。
ログアウト
admin
ドロップリストをクリックしSign out
を選択、ログアウトする。
ログイン
上述のURLにアクセスするとログインダイアログが出現する。画面上部のロゴ領域がMYREALM
になっている。
test000
/yourpassword
を入力してSign in
をクリックすると、先ほど設定した個人情報を確認できる。
またプライベートウィンドウ(シークレットウィンドウ)などで、別途admin console( http://localhost:8080 )にアクセスし、test000ユーザーのSessions
タブを確認すると、セッションができていることを確認できる。
別PCからアクセス
以下記事にならって、Keycloakを起動したPCに外部(Laravelを起動するPC)からアクセスできるように設定しておく。
なおこのPCの外部IPをa.b.c.d
のように以下記載する。実際は192.168.0.18
のようなものとなる。
Laravel
ダウンロードと初期設定
ここに記載の通り(docker)にすすめる(Breezeをインストールしてログインできるところまで)。
> curl -s "https://laravel.build/chirper" | bash
> cd chirper
> ./vendor/bin/sail up -d
> ./vendor/bin/sail artisan migrate
> ./vendor/bin/sail composer require laravel/breeze --dev
> ./vendor/bin/sail php artisan breeze:install blade
> ./vendor/bin/sail npm run dev
# Ctfl + Cでキャンセル
キャンセル前にブラウザでlocalhostにアクセスすれば、以下のような画面を確認できる。
Socialite Providersのインストール
つづいてSocialiteProvidersをインストールする。
vendor/bin/sail composer require socialiteproviders/keycloak
以降、Laravel側にコードを追加していく。
.env
に以下の項目を追加
KEYCLOAK_CLIENT_ID="sample-client"
KEYCLOAK_CLIENT_SECRET="xxxxxxxx"
KEYCLOAK_REDIRECT_URI="http://localhost/auth/keycloak/callback"
KEYCLOAK_BASE_URL="http://a.b.c.d:8080/"
KEYCLOAK_REALM="myrealm"
-
KEYCLOAK_CLIENT_SECRET
の"xxxxxxxx"
は、実際の値に置き換える。 -
KEYCLOAK_BASE_URL
のa.b.c.d
はKeycloakを立ち上げたPCのIPアドレスに置き換える。
config/services.php
に以下追加
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
// ここから追加
'keycloak' => [
'client_id' => env('KEYCLOAK_CLIENT_ID'),
'client_secret' => env('KEYCLOAK_CLIENT_SECRET'),
'redirect' => env('KEYCLOAK_REDIRECT_URI'),
'base_url' => env('KEYCLOAK_BASE_URL'),
'realms' => env('KEYCLOAK_REALM'),
],
// ここまで追加
Laravel10以前の場合
Laravel10以前の場合の詳細を見る
config/app.php
に以下追加
/* 前略 */
'providers' => ServiceProvider::defaultProviders()->merge([
/* 中略 */
App\Providers\RouteServiceProvider::class,
/* ここから追加 */
//Laravel\Socialite\SocialiteServiceProvider::class,
\SocialiteProviders\Manager\ServiceProvider::class,
/* ここまで追加 */
])->toArray(),
/* 後略 */
app/Providers/EventServiceProvider.php
以下を追加
protected $listen = [
/* ここから */
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
\SocialiteProviders\Keycloak\KeycloakExtendSocialite::class.'@handle',
],
/* ここまで */
Registered::class => [
SendEmailVerificationNotification::class,
],
];
Laravel11以上の場合
bootstrap/provider.php
に以下追加
<?php
return [
App\Providers\AppServiceProvider::class,
/* ここから追加 */
\SocialiteProviders\Manager\ServiceProvider::class,
/* ここまで追加 */
];
app/Providers/AppServiceProvider.php
に以下追加
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
/* ここから追加 */
use Illuminate\Support\Facades\Event;
/* ここまで追加 */
boot
メソッドに以下コードを追加する。
/**
* Bootstrap any application services.
*/
public function boot(): void
{
/* ここから追加 */
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
$event->extendSocialite('keycloak', \SocialiteProviders\Keycloak\Provider::class);
});
/* ここまで追加 */
}
app/Http/Controllers/KeycloakLoginController.php
以下内容のコントローラを新規追加する。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;
use Socialite;
use App\Models\User;
class KeycloakLoginController extends Controller
{
public function redirectToKeycloak()
{
return Socialite::driver('keycloak')->redirect();
}
public function handleKeycloakCallback()
{
$keycloakUser = Socialite::driver('keycloak')->stateless()->user();
$user = User::where('email', $keycloakUser->email)->first();
if ($user==null) {
$user = $this->createUser($keycloakUser);
}
Auth::login($user, true);
return redirect('/dashboard');
}
public function createUser($keycloakUser)
{
dd ( $keycloakUser );
$user = User::create([
'name' => $keycloakUser->user['name'],
'email' => $keycloakUser->user['email'],
'password' => Hash::make(uniqid()),
]);
return $user;
}
}
routes/web.php
以下ルートを追加する。
<?php
use App\Http\Controllers\ProfileController;
/* ここから */
use App\Http\Controllers\KeycloakLoginController;
/* ここまで */
use Illuminate\Support\Facades\Route;
// redirect to keycloak
Route::get('/auth/keycloak', [KeycloakLoginController::class, 'redirectToKeycloak'])
->name('login.keycloak');
// after authentication
Route::get('/auth/keycloak/callback', [KeycloakLoginController::class, 'handleKeycloakCallBack'])
->name('login.keycloak.callback');
resources\views\auth\login.blade.php
以下コードを追加し、ログイン画面にKeycloakのアイコンを加える。
<x-primary-button class="ml-3">
{{ __('Log in') }}
</x-primary-button>
</div>
</form>
<!-- ここから -->
<div class="flex items-center justify-end mt-4">
<a href="{{ route('login.keycloak') }}" class="ml-3 inline-flex items-center">
<img src="https://upload.wikimedia.org/wikipedia/commons/2/29/Keycloak_Logo.png" style="margin-left: 3em; width: 64px; height: 64px">
</a>
</div>
<!-- ここまで -->
</x-guest-layout>
SSO動作確認
Keycloakログイン済みの場合
以下Laravelを立ち上げたPCにて操作する。
-
まず、Keycloakのセッション情報をブラウザに保存するため、Keycloakにログインする。
-
プライベートモードなどで別途ブラウザを立ち上げて、admin consoleにログインしてセッションがあることを確認する。
-
http://a.b.c.d:8080
-
a.b.c.d
はKeycloakを立ち上げているPCのIPアドレスに置き換える。
-
- レルム:myrealm
- Clients --> sample-client --> Sessions
- なにかセッションがあればOK
-
http://a.b.c.d:8080
-
1項とおなじブラウザでローカルのLaravelにアクセスする。
-
画面上の
Log in
リンクからログイン画面に遷移し、LOG IN
ボタン下のKeycloakアイコンを選択する(画面上のEmail
欄やPassword
欄にはなにも入力しない)。
-
なお
app/Http/Controllers/KeycloakLoginController.php
に追加したコードからdd ( $keycloakUser );
の行をコメントアウトすると以下の画面となる。
-
Laravel側で
Log out
する。- ちなみに、Laravel側UIで
Log out
を操作しても(Laravel側で未実装のため)Keycloak側ではログアウトしていない。
- ちなみに、Laravel側UIで
Keycloak未ログインの場合
- Keycloak未ログインの状態で、ローカルのLaravelにアクセスする。
- 画面上のLoinリンクからログイン画面に遷移し、
LOG IN
ボタン下のKeycloakアイコンを選択する。 - リダイレクトが発生し、Keycloakのログイン画面を表示する。
-
test000
/yourpassword
でログインし、前節5項(あるいは6項)と同様の画面を得ることができる。
まとめ
この記事では、Keycloakを使ったSSOおよびユーザ情報の取得をLaravelで実現する方法をまとめた。
Keycloakの構成は、試行錯誤で行ったものであるので本格的に使う場合は別書を参考にしてほしい。