💎

@AuthenticationPrincipalをラップしたい

2023/12/27に公開

どうしてそう思ったか

ユーザー情報などを管理するDBが以下のようになっていました。

この構造は、1人のユーザーがroleを複数持つ場合のDB構造なんですが、この構造が1人のユーザーに対して1個のロールしか割り当てられない場合でも使われていました。

そして、ロールごとにユーザー情報として別々の情報を持つようになっていたため、最終的に以下のようなDB構造になっていました。

この時、AuthenticationPrincipalをそのまま使うと、以下のようなコードがロールごとに大量に書かれることになります。

@GetMapping(value = "")
public String hoge(@AuthenticationPrincipal User user) {
	String name = user.getRole1User().role1UserName;
}

このuser.getRole1Userの部分を毎回書くのが面倒なため、AuthenticationPrincipalをラップして一発でRole1Userのエンティティを取れるようにすることが目的です。

実装

まずAuthenticationPrincipalをラップしたアノテーションを作成します。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@AuthenticationPrincipal(expression = "@role1UserPrincipalExtractor.extract(#this)")
public @interface Role1UserPrincipal {

}

次に実際に処理を行うクラスを作成します。

@Component("role1UserPrincipalExtractor")
public class Role1UserPrincipalExtractor {
	public KTGeneralDetail extract(User user) {
        return user.getRole1User();
    }
}

これでメソッドを次のように書き換えれば、一発でrole1Userが持って来れるようになります。

@GetMapping(value = "")
public String hoge(@Role1UserPrincipal Role1User role1User) {
	String name = role1User.role1UserName;
}

どうしてこれで実装ができているのか

AuthenticationPrincipalの引数のexpressionには SpEL式 を記述することができます。
以下のコードは、role1UserPrincipalExtractorというBeanの、extractメソッドを呼び出す、という処理になっています。(#thisはAuthenticationPrincipalで取得されたUserのエンティティになります。)

@role1UserPrincipalExtractor.extract(#this)

よって、Role1UserPrincipalExtractor.extractメソッドが呼び出され、role1Userを取得することができます。

Discussion