4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SpringBootでログイン中のユーザーのUserDetailsクラスを継承したクラスの情報を取得したい

Last updated at Posted at 2021-01-19

###2021/07/25に追記しました
最後に簡単な方法を追記しました。

###環境
Spring Boot 2.4.0
java 1.8
thymeleaf 3.0.11
Spring Security 2.4.0

###実現したいこと
ログイン中のユーザーのUSERDETAILSを継承したクラスの情報を取得したい。

###いろいろ試してなんとか実現
ほぼ丸一日かかりました。というかちゃんとSpringBootを理解していないのだとは思いますが、いろんなサイトを見て試してみてなんとかうまく行ったので、記録として残しておきます。

###USERDETAILSを継承しているクラス

Tenantsクラス
Staffクラス

###ログイン認証
MyUserDetailsServiceクラスのloadUserByUsernameメソッドで、返すクラスを分けています。

MyUserDetailsServiceクラス
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// 引数がnullなら例外を投げる
    if (Objects.isNull(username)) {
      throw new UsernameNotFoundException("username is empty");
	  }
    Tenants tenants = tenantRepository.findByAdminId(username);
    Staff staff = staffRepository.findByEmail(username);
    // nullが返ってきたら例外を投げる
    if(tenants != null) {
    	return tenants;
    } else if(staff != null) {
    	return staff;
    } else {
    	throw new UsernameNotFoundException("Not found username: " + username);
    }

	}

###コントローラー
ログイン後のトップ画面を表示するコントローラーで、今どのクラスでログイン認証されているか表示したい

いろいろ試した結果、下の実装で、どのクラスで認証されているか取得できるようになりました。

@GetMapping("/top")
public ModelAndView userTop(eModelAndView mv, Principal principal) {
	
        // ログイン中のユーザーのUSERDETAILSを継承したクラスを取得する
	Authentication auth = (Authentication) principal;
	String authClass = auth.getPrincipal().getClass().getSimpleName();
	if(authClass.equals("Tenants")) {
		System.out.println("テナントクラスだぜ!!");
		String tenantId = ((Tenants)auth.getPrincipal()).getId().toString();
		httpServletResponse.addCookie(new Cookie("tenantId", tenantId));
	}
	if(authClass.equals("Staff")) {
		System.out.println("スタッフクラスやっちゅうねん!!");
		String tenantId = ((Staff)auth.getPrincipal()).getTenantId().toString();
		httpServletResponse.addCookie(new Cookie("tenantId", tenantId));
	}
}

###ハマったところ
PrincipalやAuthenticationなどの使いかたがよくわからなくて、
・引数の渡し方
@AuthenticationPrincipalアノテーションの使い方
・キャストが必要?
・PrincipalにTenantsクラス入ってるけど、フィールドが取り出せないよ?
・getClass()がコード・アシスタントで出てくるのにエラーが出て実行できないよ?
などなど。。。

どうやらPrincipalにはUserDetailsを継承したクラスの、認証がうまく行ったときのレコードが全部入っているようでした。

しかし、username以外は取り出せないということに。。。

Principalを使えば良いとばかり思っていたけど、どうやら違った。

Authenticationクラスの中にPrincipalクラスが入っていて、Principalの中にUserDetailsクラスが入っているイメージでした。(合っているかわかりません)

ただそのイメージで

// コントローラーの引数に渡しているPrincipalからまずAuthenticationを取得する
Authentication auth = (Authentication) principal;
String authClass = auth.getPrincipal() // Principalを取得
   .getClass() // クラスを取得
   .getSimpleName(); // パッケージ名を除外

この流れでうまくいきました。

最初の
Principal → Authenticationへのキャストが必要なの??って感じでしたが、これをやらないとうまく行かなかった。

###thymeleafでビューで表示する方法

<div sec:authentication="principal"></div>
<div th:text="${#authentication.principal}"></div>

いずれも同じ内容が表示されます。コントローラーで取得するようりも遥かに簡単に取得できます。

そしてちゃんとprincipalにはUserDetailsが入っているのが確認できます。

###まとめ

  • コントローラー引数に Principal principalを渡す
  • Authenticationから.getPrincipal()でPrincipalを取得
  • thymeleafでは<div sec:authentication="principal"></div>
  • または<div th:text="${#authentication.principal}"></div>
// コントローラー
// 引数に Principal principalを渡す
public ModelAndView userTop(ModelAndView mv, Principal principal) {
// コントローラー
// 引数に Principal principalを渡す
Authentication auth = (Authentication) principal;
// AuthenticationからPrincipalを取得
String authClass = auth.getPrincipal()
   .getClass()
   .getSimpleName();

2021/07/25追記
###もっと簡単な方法がありました

####前提
User.javaクラスはUserDetailsを継承している。

###コントローラーで認証したUserを取得する

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.annotation.AuthenticationPrincipal;

public String userTop(
  HttpServletResponse httpServletResponse,
  @AuthenticationPrincipal User user) {
  
  //  ユーザIDをクッキーに保存
  httpServletResponse.addCookie(new Cookie("userId", user.getId().toString()));

  return "top";
}

つまり、コントローラーのメソッドの引数の
@AuthenticationPrincipal User user
の時点ですでにUserクラスにキャストされているので、自由に取り出せる!!

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?