Keycloakには、ユーザー属性を追加することができます。「この情報を一括出力したい」という要望があったので、方法を探しましたが、どうやら標準機能では付いてなさそう。
なければ作るしかないので、作ることにしました。
DBでユーザー属性のデータを確認
ユーザー属性は、「USER_ATTRIBUTE」テーブルにあることがわかってるので、早速検索。
SELECT文
SELECT * FROM KEYCLOAK.USER_ATTRIBUTE;
出力結果(※一部マスクしています)
Keycloakでは、ユーザー属性をユーザーごとに項目を設定できる仕様となっています。そのため、「key-value」のようにデータを持つ必要があり、縦持ちでデータが格納されていることがわかります。
一方、一括出力の結果としては、ユーザーのキーを一番左において、属性の項目を横並びにしたいです。
SELECT文でやるなら
SELECT キー, 項目1, 項目2, 項目3,…
のようにすれば一応できます。
ですが、属性の項目を追加したら、その都度、SELECT文にカラムを増やさないといけないです。
それだとメンテナンスに手間がかかるので、ストアドプロシージャで対応することにしました。
ストアドプロシージャの作成
縦持ちのデータを横持ちにするため、temporaryテーブルを作成します。
イメージは以下の通り。
実現方法は、以下にしました。
- 「USER_ATTRIBUTE」テーブルからユーザー属性にある項目の種類を取得
- ユーザーIDと取得した項目の種類をカラムとするtemporaryテーブルを作成
- ユーザーIDと「USER_ATTRIBUTE」テーブルを使って、temporaryテーブルを更新
- temporaryテーブルをSELECTする
作成したプログラムは以下の通り。※idの他にユーザー名もほしいので、ユーザー情報と紐づけています。
ストアドプロシージャ(psql)
CREATE OR REPLACE PROCEDURE keycloak.get_user_at(
)
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
-- ユーザー属性(ATTRIBUTE)のカーソル
AT_CUR CURSOR FOR
SELECT NAME
FROM KEYCLOAK.USER_ATTRIBUTE
GROUP BY NAME
ORDER BY 1;
DECLARE
-- ユーザー情報のカーソル
ID_CUR CURSOR FOR
SELECT ID, USERNAME
FROM KEYCLOAK.USER_ENTITY;
-- ユーザー情報とATTRIBUTEのカーソル
ID_AT_CUR CURSOR FOR
SELECT USER_ID, NAME, VALUE
FROM KEYCLOAK.USER_ATTRIBUTE;
-- ATTRIBUTEカラムを作るための文字列
CREATE_AT_STR CHARACTER VARYING(5000) := '';
UP_QUERY CHARACTER VARYING(5000) := '';
BEGIN
-- 登録されているATTRIBUTEでループ
FOR AT IN AT_CUR LOOP
CREATE_AT_STR = CREATE_AT_STR || AT.NAME || ' CHARACTER VARYING(255),';
END LOOP;
CREATE_AT_STR = TRIM(CREATE_AT_STR, ',');
-- ATTRIBUTEを「横軸(列)」にした一時テーブルを作成
EXECUTE 'CREATE TEMP TABLE IF NOT EXISTS TEMP_AT(ID CHARACTER VARYING(255), USERNAME CHARACTER VARYING(255),'|| CREATE_AT_STR ||');';
-- 一時テーブルにユーザー情報を登録
FOR ID IN ID_CUR LOOP
INSERT INTO TEMP_AT(ID, USERNAME) VALUES(ID.ID, ID.USERNAME);
END LOOP;
-- 一時テーブルのATTRIBUTEを更新
FOR ID_AT IN ID_AT_CUR LOOP
UP_QUERY = 'UPDATE TEMP_AT SET ' || ID_AT.NAME || ' = ''' || ID_AT.VALUE || ''' WHERE ID = ''' || ID_AT.USER_ID || '''';
EXECUTE UP_QUERY;
END LOOP;
END;
$BODY$;
プロシージャの実行プロシージャの結果
作成したプロシージャを実行して結果を確認します。
プロシージャの実行 & 結果出力
CALL KEYCLOAK.GET_USER_AT();
SELECT * FROM TEMP_AT;
出力結果(※一部マスクしています)
いい感じに出力されました!
まとめ
今回は、Keycloakのユーザー属性を一括で出力する機能を作成しました。縦持ちデータを横持ちにすることは、今後もありそうなので、応用が利きそうです。
コメント