未認証ユーザの認可エラー時の挙動

未認証ユーザの認可エラー時の挙動と、その変更方法について。

デフォルトの挙動

未認証ユーザ(ログインしていないユーザ)が権限の必要なURLにアクセスした際、デフォルトではログインページにリダイレクトされます。

この時Spring Securityでは、AuthenticationEntryPointインターフェースのメソッドを呼び出してエラー応答を行っています。
フォームで認証を行う場合、デフォルトはLoginUrlAuthenticationEntryPointクラスが呼び出されます。
このクラスによりログインページにリダイレクトされるようになっています。

この挙動の事を忘れて以下のようなテストコードを書いてしまい、アサートエラーに悩まされました。

@Test
@WithAnonymousUser
public void 非ログイン状態で削除() throws Exception {
	
	mockMvc.perform(post(new URI("/list/delete/1")))
		.andExpect(status().isForbidden());	// アクセス可否を検証
}

その時のエラーが以下のようなものです。

java.lang.AssertionError: Status expected:<403> but was:<302>

ログイン画面にリダイレクトせず、403エラーを返すには?

ExceptionHandlingConfigurer<H> authenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint)に適切なAuthenticationEntryPointを指定します。
Http403ForbiddenEntryPointクラスなど、Spring Security側で用意しているクラスがいくつかあります。
AuthenticationEntryPointインターフェースを実装して、独自のクラスを作成して使うこともできるようです。

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		
		// 省略
		
		// 未認証時のアクセス拒否の設定
		http
			.exceptionHandling()
			    .authenticationEntryPoint(new Http403ForbiddenEntryPoint());
		
		// 省略
	}
}

余談

今回認可のテストを行うために403エラーを返すようにしましたが、デフォルトの実装のようにログイン画面にリダイレクトさせる方がアプリの挙動としてはいいかと思います。
以下のようにテスト用のJava Configを用意する方法もあるようなので、テストの時だけ今回のような対応を取るのがいいのかもしれません。

  1. Java Configに@TestConfigurationを指定する。
  2. テストのクラスに@Importを使用して、コンフィグを指定する。

参考