[postgreSQL][Keycloak] ユーザー属性を一括出力してみた(縦持ちのデータを横持ちで表示する)

スポンサーリンク
Keycloak

Keycloakには、ユーザー属性を追加することができます。「この情報を一括出力したい」という要望があったので、方法を探しましたが、どうやら標準機能では付いてなさそう。

なければ作るしかないので、作ることにしました。

DBでユーザー属性のデータを確認

ユーザー属性は、「USER_ATTRIBUTE」テーブルにあることがわかってるので、早速検索。

SELECT文

SELECT * FROM KEYCLOAK.USER_ATTRIBUTE;

出力結果(※一部マスクしています)

Keycloakでは、ユーザー属性をユーザーごとに項目を設定できる仕様となっています。そのため、「key-value」のようにデータを持つ必要があり、縦持ちでデータが格納されていることがわかります。

一方、一括出力の結果としては、ユーザーのキーを一番左において、属性の項目を横並びにしたいです。

SELECT文でやるなら

SELECT キー, 項目1, 項目2, 項目3,…

のようにすれば一応できます。

ですが、属性の項目を追加したら、その都度、SELECT文にカラムを増やさないといけないです。

それだとメンテナンスに手間がかかるので、ストアドプロシージャで対応することにしました。

ストアドプロシージャの作成

縦持ちのデータを横持ちにするため、temporaryテーブルを作成します。

イメージは以下の通り。

実現方法は、以下にしました。

  1. 「USER_ATTRIBUTE」テーブルからユーザー属性にある項目の種類を取得
  2. ユーザーIDと取得した項目の種類をカラムとするtemporaryテーブルを作成
  3. ユーザーIDと「USER_ATTRIBUTE」テーブルを使って、temporaryテーブルを更新
  4. 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のユーザー属性を一括で出力する機能を作成しました。縦持ちデータを横持ちにすることは、今後もありそうなので、応用が利きそうです。

コメント

タイトルとURLをコピーしました