0
1

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.

UsernamePasswordAuthenticationFilter を継承したクラスを使ったらセッションIDが変わらなかった時のメモ

Last updated at Posted at 2021-10-10

Spring SecurityUsernamePasswordAuthenticationFilter はユーザー名/パスワードを使って認証を行うフィルタです。

リクエストの本文がJSONの時はこのままではうまくいきません。(HttpServletRequest#getParameter を使っているため)
なので、このクラスを継承した自前のクラスを作成しました。(このフィルタクラス自体の内容は省略)

この自前のクラスを登録するときに


	@Override
	protected void configure(HttpSecurity http) throws Exception {
    //省略

		JsonBodyUsernamePasswordAuthenticationFilter f = new JsonBodyUsernamePasswordAuthenticationFilter();
    //いくつか省略
		http.addFilterAt(f, UsernamePasswordAuthenticationFilter.class);
	}

としていたのですが、これだと一部の機能が UsernamePasswordAuthenticationFilter と同じようには動きません。
(例 ログイン成功時にセッションIDが変更されないなど)

この問題の対処のメモを書きます。

  • Spring Boot のバージョンは2.5.5
  • Spring Security のバージョンは5.5.2

です。

先に結論

フィルターの登録には 上記の方法は使わず FormLoginConfigurer を参考に AbstractAuthenticationFilterConfigurer を継承したクラスを作成し、このクラス経由でフィルターを登録するようにしました。

コード例

public class JsonBodyLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
		AbstractAuthenticationFilterConfigurer<H, JsonBodyLoginConfigurer<H>, JsonBodyUsernamePasswordAuthenticationFilter> {

	public JsonBodyLoginConfigurer() {
		super(new JsonBodyUsernamePasswordAuthenticationFilter(), null);
	}

	@Override
	public JsonBodyLoginConfigurer<H> loginPage(String loginPage) {
		return super.loginPage(loginPage);
	}

	@Override
	protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
		return new AntPathRequestMatcher(loginProcessingUrl, "POST");
	}

}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
    //省略
		http.apply(new JsonBodyLoginConfigurer<>())
				.loginPage("/login")
				.loginProcessingUrl("/login")
				.permitAll()
        //省略
	}

これで ログイン成功時にセッションIDが変更されるようになりました。

セッションIDの変更はどこでされているのか?

ChangeSessionIdAuthenticationStrategy で行われています。

このメソッドは AbstractAuthenticationProcessingFilter (UsernamePasswordAuthenticationFilter の親クラス)で認証成功時に呼ばれるようになっています。

UsernamePasswordAuthenticationFilter で検証したときは CompositeSessionAuthenticationStrategy で集約されており、他には CsrfAuthenticationStrategy が含まれていました。

(この CompositeSessionAuthenticationStrategy はどこで作られているかは追ってないです)

なぜ セッションIDが変更されなかったのか?

AbstractAuthenticationProcessingFilter で宣言されている sessionStrategy フィールド

private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();

NullAuthenticatedSessionStrategy のままになっていました。

このため、認証に成功した場合もセッションIDの変更が行われないままになっていました。

sessionStrategy はどこでセットされるのか

コードを追いかけたところ AbstractAuthenticationFilterConfigurer#configure メソッドで セットされていました。

このメソッドでは SessionAuthenticationStrategy 以外の クラスもセットしているようです。

addFilterAt で登録したときは、これらのクラスのセットが行われていなかったので、セッションIDの変更が行われなかったようです。

じゃあどうしようか?🤔

ここで設定しているように http.getSharedObject(SessionAuthenticationStrategy.class)WebSecurityConfigurerAdapter の継承クラスのconfigure メソッドで使おうとしましたが、このタイミングでは get してもまだ設定されていないので null が返却されます。

悩んだ結果 AbstractAuthenticationFilterConfigurer の継承クラスを使うのが良いと思い、最初に記載した方法になりました。

終わり

この方法が正しいかどうかもわかりませんが、とりあえずメモとして残しておきます。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?