フォームログイン

Spring Security は、HTML フォームを介して提供されるユーザー名とパスワードのサポートを提供します。このセクションでは、Spring Security 内でフォームベース認証がどのように機能するかについて詳しく説明します。

このセクションでは、フォームベースのログインが Spring Security 内でどのように機能するかを調べます。まず、ユーザーがログインフォームにリダイレクトされる方法を確認します。

loginurlauthenticationentrypoint
図 1: ログインページへのリダイレクト

前の図は、SecurityFilterChain 図を基にしています。

number 1 最初に、ユーザーは、認可されていないリソース(/private)に対して認証されていないリクエストを行います。

number 2Spring Security の AuthorizationFilter は、認証されていないリクエストが AccessDeniedException をスローすることによって拒否されたことを示します。

number 3 ユーザーが認証されていないため、ExceptionTranslationFilter は認証の開始を開始し、構成された AuthenticationEntryPoint を使用してログインページにリダイレクトを送信します。ほとんどの場合、AuthenticationEntryPoint は LoginUrlAuthenticationEntryPoint (Javadoc) のインスタンスです。

number 4 ブラウザーは、リダイレクト先のログインページをリクエストします。

number 5 アプリケーション内の何かが、ログインページをレンダリングする必要があります。

ユーザー名とパスワードが送信されると、UsernamePasswordAuthenticationFilter はユーザー名とパスワードを認証します。UsernamePasswordAuthenticationFilter は AbstractAuthenticationProcessingFilter を継承するため、次の図は非常によく似ているはずです。

usernamepasswordauthenticationfilter
図 2: ユーザー名とパスワードの認証

この図は、SecurityFilterChain ダイアグラムから構築されています。

number 1 ユーザーがユーザー名とパスワードを送信すると、UsernamePasswordAuthenticationFilter は、HttpServletRequest インスタンスからユーザー名とパスワードを抽出することにより、Authentication の一種である UsernamePasswordAuthenticationToken を作成します。

number 2 次に、UsernamePasswordAuthenticationToken が AuthenticationManager インスタンスに渡され、認証されます。AuthenticationManager がどのように見えるかの詳細は、ユーザー情報がどのように保存されているかによって異なります。

number 3 認証が失敗した場合、Failure

  1. SecurityContextHolder はクリアされます。

  2. RememberMeServices.loginFail が呼び出されます。設定されていないことを覚えている場合、これはノーオペレーションです。Javadoc の RememberMeServices (Javadoc) インターフェースを参照してください。

  3. AuthenticationFailureHandler が呼び出されます。Javadoc の AuthenticationFailureHandler (Javadoc) クラスを参照してください

number 4 認証が成功した場合は、Success .

  1. SessionAuthenticationStrategy には新しいログインが通知されます。Javadoc の SessionAuthenticationStrategy (Javadoc) インターフェースを参照してください。

  2. 認証SecurityContextHolder にセットされています。Javadoc の SecurityContextPersistenceFilter (Javadoc) クラスを参照してください。

  3. RememberMeServices.loginSuccess が呼び出されます。設定されていないことを覚えている場合、これはノーオペレーションです。Javadoc の RememberMeServices (Javadoc) インターフェースを参照してください。

  4. ApplicationEventPublisher は InteractiveAuthenticationSuccessEvent を公開します。

  5. AuthenticationSuccessHandler が呼び出されます。通常、これは SimpleUrlAuthenticationSuccessHandler であり、ログインページにリダイレクトすると、ExceptionTranslationFilter によって保存されたリクエストにリダイレクトされます。

デフォルトでは、Spring Security フォームログインが有効になっています。ただし、サーブレットベースの構成が提供されるとすぐに、フォームベースのログインを明示的に提供する必要があります。次の例は、最小限の明示的な Java 構成を示しています。

フォームログイン
  • Java

  • XML

  • Kotlin

public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		.formLogin(withDefaults());
	// ...
}
<http>
	<!-- ... -->
	<form-login />
</http>
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
	http {
		formLogin { }
	}
	// ...
}

上記の構成では、Spring Security はデフォルトのログインページをレンダリングします。ほとんどの本番アプリケーションには、カスタムログインフォームが必要です。

次の構成は、カスタムログインフォームを提供する方法を示しています。

カスタムログインフォームの構成
  • Java

  • XML

  • Kotlin

public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		.formLogin(form -> form
			.loginPage("/login")
			.permitAll()
		);
	// ...
}
<http>
	<!-- ... -->
	<intercept-url pattern="/login" access="permitAll" />
	<form-login login-page="/login" />
</http>
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
	http {
		formLogin {
			loginPage = "/login"
			permitAll()
		}
	}
	// ...
}

ログインページが Spring Security 構成で指定されている場合、ページをレンダリングするのはユーザーの責任です。次の Thymeleaf (英語) テンプレートは、/login のログインページに準拠する HTML ログインフォームを生成します。

ログインフォーム - src/main/resources/templates/login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
	<head>
		<title>Please Log In</title>
	</head>
	<body>
		<h1>Please Log In</h1>
		<div th:if="${param.error}">
			Invalid username and password.</div>
		<div th:if="${param.logout}">
			You have been logged out.</div>
		<form th:action="@{/login}" method="post">
			<div>
			<input type="text" name="username" placeholder="Username"/>
			</div>
			<div>
			<input type="password" name="password" placeholder="Password"/>
			</div>
			<input type="submit" value="Log in" />
		</form>
	</body>
</html>

デフォルトの HTML フォームにはいくつかの重要なポイントがあります。

  • フォームは post から /login を実行する必要があります。

  • フォームには、Thymeleaf によって自動的に含まれる CSRF トークンを含める必要があります。

  • フォームでは、username という名前のパラメーターでユーザー名を指定する必要があります。

  • フォームでは、password という名前のパラメーターでパスワードを指定する必要があります。

  • error という名前の HTTP パラメーターが見つかった場合は、ユーザーが有効なユーザー名またはパスワードを提供できなかったことを示しています。

  • logout という名前の HTTP パラメーターが見つかった場合は、ユーザーが正常にログアウトしたことを示しています。

多くのユーザーは、ログインページをカスタマイズする以上のことは必要ありません。ただし、必要に応じて、前に示したすべてを追加の構成でカスタマイズできます。

Spring MVC を使用する場合は、GET /login を作成したログインテンプレートにマップするコントローラーが必要です。次の例は、最小の LoginController を示しています。

LoginController
  • Java

  • Kotlin

@Controller
class LoginController {
	@GetMapping("/login")
	String login() {
		return "login";
	}
}
@Controller
class LoginController {
    @GetMapping("/login")
    fun login(): String {
        return "login"
    }
}