7.9. 実装ストラテジーのインポート
ユーザーストレージプロバイダーを実装する場合は、別のストラテジーを使用できます。ユーザーフェデレーションストレージを使用する代わりに、Red Hat build of Keycloak のビルトインユーザーデータベースでユーザーをローカルで作成し、外部ストアからこのローカルコピーに属性をコピーします。この方法には多くの利点があります。
- 基本的に、Red Hat build of Keycloak は外部ストアの永続ユーザーキャッシュになります。ユーザーがインポートされると、外部ストアに到達できなくなるため、負荷はなくなります。
- 公式ユーザーストアとして Red Hat build of Keycloak に移行し、古い外部ストアを非推奨にする場合は、アプリケーションを徐々に移行して Red Hat build of Keycloak を使用できます。すべてのアプリケーションが移行されたら、インポートされたユーザーのリンクを解除し、古いレガシー外部ストアを破棄します。
インポートストラテジーの使用には、いくつかの明確な欠点があります。
- 初めてユーザーを検索するには、Red Hat build of Keycloak データベースを複数回更新する必要があります。これを実行すると、負荷がかかってパフォーマンスが大幅に低下し、Red Hat build of Keycloak データベースに大きな負担がかかる可能性があります。ユーザーフェデレーションされたストレージアプローチは、必要に応じて追加のデータのみを保存し、外部ストアの機能によっては使用されない可能性があります。
- このインポート方法では、ローカルの Red Hat build of Keycloak ストレージと外部ストレージを同期する必要があります。User Storage SPI には同期をサポートするために実装できる機能インターフェイスがありますが、この操作はすぐに面倒で複雑になる可能性があります。
インポートストラテジーを実装するには、ユーザーがローカルにインポートされているかどうかを最初に確認します。ローカルにインポートされている場合には、ローカルユーザーを返します。インポートされていない場合には、ローカルにユーザーを作成して、外部ストアからデータをインポートします。また、ほとんどの変更が自動同期されるように、ローカルユーザーをプロキシー化することも可能です。
これは少し複雑になりますが、PropertyFileUserStorageProvider を拡張してこのアプローチを取ることができます。最初に createAdapter() メソッドを修正します。
PropertyFileUserStorageProvider
この方法では、UserStoragePrivateUtil.userLocalStorage(session) メソッドを呼び出して、ローカルの Red Hat build of Keycloak ユーザーストレージへの参照を取得します。ユーザーがローカルに保存されているかどうかを確認し、ない場合はローカルに追加します。ローカルユーザーの id を設定しないでください。id は、Red Hat build of Keycloak が自動生成します。また、UserModel.setFederationLink() を呼び出して、プロバイダーの ComponentModel に ID を渡すことにも注意してください。これにより、プロバイダーとインポートされたユーザーの間にリンクが設定されます。
ユーザーストレージプロバイダーが削除されると、そのストレージプロバイダーによってインポートされたユーザーも削除されます。これは、UserModel.setFederationLink() を呼び出す目的の 1 つです。
また、ローカルユーザーがリンクしている場合は、CredentialInputValidator インターフェイスおよび CredentialInputUpdater インターフェイスから実装するメソッドのために、ストレージプロバイダーが依然として委譲される点に留意してください。検証または更新で false が返されると、Red Hat build of Keycloak はローカルストレージを使用して検証または更新できるか確認します。
また、org.keycloak.models.utils.UserModelDelegate クラスを使用してローカルユーザーをプロキシー処理している点に注意してください。このクラスは UserModel の実装です。すべてのメソッドは、それがインスタンス化された UserModel に委譲するだけです。プロパティーファイルと自動的に同期するため、この委譲クラスの setUsername() メソッドが上書きされます。プロバイダーの場合、これを使用して、ローカル UserModel 上の他のメソッドを 傍受 して、外部ストアと同期できます。たとえば、get メソッドでは、ローカルストアが同期していることを確認することができます。set メソッドでは、外部ストアがローカルストアと同期し続けます。getId() メソッドは、ユーザーをローカルで作成したときに自動生成された id を常に返す必要がある点に留意してください。インポート以外の他の例で示されているように、フェデレーション ID は返さないはずです。
プロバイダーが UserRegistrationProvider インターフェイスを実装している場合、removeUser() メソッドはローカルストレージからユーザーを削除する必要はありません。ランタイムはこの操作を自動的に実行します。また、ローカルストレージから削除される前に removeUser() が呼び出されることに注意してください。
7.9.1. ImportedUserValidation インターフェイス リンクのコピーリンクがクリップボードにコピーされました!
この章の最初の部分で、ユーザーへの問い合わせがどのように機能するかを説明しました。最初にローカルストレージを問い合わせし、ユーザーが見つかった場合は、クエリーが終了します。これは、上記の実装で問題になります。ローカル UserModel をプロキシーして、ユーザー名の同期を維持します。User Storage SPI には、リンクされたローカルユーザーがローカルデータベースから読み込まれるたびに実行されるコールバックがあります。
リンクされたローカルユーザーが読み込まれるたびに、ユーザーストレージプロバイダークラスがこのインターフェイスを実装している場合は、validate() メソッドが呼び出されます。ここでは、ローカルユーザーをパラメーターとしてプロキシー化して返すことができます。その新しい UserModel が使用されます。オプションで、ユーザーが外部ストアにまだ存在するかどうかを確認することもできます。validate() が Null を返すと、ローカルユーザーがこのデータベースから削除されます。
7.9.2. ImportSynchronization インターフェイス リンクのコピーリンクがクリップボードにコピーされました!
インポートストラテジーにより、ローカルユーザーコピーが外部ストレージと同期できなくなっていることがわかります。おそらくユーザーは外部ストアから削除されてしまっているようです。ユーザーストレージ SPI には、これに対応するために実装できる追加のインターフェイス (org.keycloak.storage.user.ImportSynchronization) があります。
このインターフェイスはプロバイダーファクトリーによって実装されます。このインターフェイスがプロバイダーファクトリーによって実装されると、プロバイダーの管理コンソール管理ページには追加オプションが表示されます。ボタンをクリックして、手動で強制的に同期させることができます。これにより、ImportSynchronization.sync() メソッドが呼び出されます。また、同期を自動的にスケジュールできる追加の設定オプションが表示されます。自動同期は syncSince() メソッドを呼び出します。