フォームログイン
Spring Security は、HTML フォームを介して提供されるユーザー名とパスワードのサポートを提供します。このセクションでは、Spring Security 内でフォームベース認証がどのように機能するかについて詳しく説明します。
このセクションでは、フォームベースのログインが Spring Security 内でどのように機能するかを調べます。まず、ユーザーがログインフォームにリダイレクトされる方法を確認します。
前の図は、SecurityFilterChain
図を基にしています。
最初に、ユーザーは、認可されていないリソース(/private
)に対して認証されていないリクエストを行います。
Spring Security の AuthorizationFilter
は、認証されていないリクエストが AccessDeniedException
をスローすることによって拒否されたことを示します。
ユーザーが認証されていないため、ExceptionTranslationFilter
は認証の開始を開始し、構成された AuthenticationEntryPoint
を使用してログインページにリダイレクトを送信します。ほとんどの場合、AuthenticationEntryPoint
は LoginUrlAuthenticationEntryPoint
(Javadoc) のインスタンスです。
ブラウザーは、リダイレクト先のログインページをリクエストします。
アプリケーション内の何かが、ログインページをレンダリングする必要があります。
ユーザー名とパスワードが送信されると、UsernamePasswordAuthenticationFilter
はユーザー名とパスワードを認証します。UsernamePasswordAuthenticationFilter
は AbstractAuthenticationProcessingFilter を継承するため、次の図は非常によく似ているはずです。
この図は、SecurityFilterChain
ダイアグラムから構築されています。
ユーザーがユーザー名とパスワードを送信すると、UsernamePasswordAuthenticationFilter
は、HttpServletRequest
インスタンスからユーザー名とパスワードを抽出することにより、Authentication
の一種である UsernamePasswordAuthenticationToken
を作成します。
次に、UsernamePasswordAuthenticationToken
が AuthenticationManager
インスタンスに渡され、認証されます。AuthenticationManager
がどのように見えるかの詳細は、ユーザー情報がどのように保存されているかによって異なります。
認証が失敗した場合、Failure。
SecurityContextHolder はクリアされます。
RememberMeServices.loginFail
が呼び出されます。設定されていないことを覚えている場合、これはノーオペレーションです。Javadoc のRememberMeServices
(Javadoc) インターフェースを参照してください。AuthenticationFailureHandler
が呼び出されます。Javadoc のAuthenticationFailureHandler
(Javadoc) クラスを参照してください
認証が成功した場合は、Success .
SessionAuthenticationStrategy
には新しいログインが通知されます。Javadoc のSessionAuthenticationStrategy
(Javadoc) インターフェースを参照してください。認証は SecurityContextHolder にセットされています。Javadoc の
SecurityContextPersistenceFilter
(Javadoc) クラスを参照してください。RememberMeServices.loginSuccess
が呼び出されます。設定されていないことを覚えている場合、これはノーオペレーションです。Javadoc のRememberMeServices
(Javadoc) インターフェースを参照してください。ApplicationEventPublisher
はInteractiveAuthenticationSuccessEvent
を公開します。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 ログインフォームを生成します。
<!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
を示しています。
Java
Kotlin
@Controller
class LoginController {
@GetMapping("/login")
String login() {
return "login";
}
}
@Controller
class LoginController {
@GetMapping("/login")
fun login(): String {
return "login"
}
}