カスタムログインページの作成を完全ガイド!初心者でもわかるSpring Securityのログイン画面自作
新人
「Spring Securityのログインページって、いつも同じ見た目なんですが、自分で作れないんですか?」
先輩
「もちろん可能だよ。ログインページをカスタマイズすれば、デザインや項目も自由にできるんだ。」
新人
「へぇ!ログイン画面って勝手に出てくるものだと思ってました。自分で作るって、何から始めればいいんですか?」
先輩
「まずは、Spring Securityの仕組みを知るところから始めよう。デフォルトのログイン画面がどんな動作をしてるかを理解すると、自作がグッと楽になるよ。」
1. なぜカスタムログインページが必要なのか?(基本的な意義)
Spring Securityを導入すると、初期状態では非常にシンプルなログイン画面が自動で生成されます。しかし、実際のWebアプリケーション開発では、自社サービスに合わせたログイン画面のデザインやレイアウトを自由に設計したいことが多くなります。
そのため、カスタムログインページ 作成の需要が高まります。独自のフォーム構造、ブランドカラー、エラーメッセージの表現など、細かいカスタマイズが可能となることで、ユーザー体験(UX)の向上にもつながります。
また、ユーザーごとにログイン時の挙動を変えたい場合(たとえば、ログイン後に特定のダッシュボードに遷移するなど)にも、ログイン画面 自作は必須の技術となります。
例えば下記のような状況に対応するために、カスタムログインは有効です:
- 企業ごとのロゴを表示したい
- デザインテンプレートに合わせたい
- メールアドレスとパスワード以外のログイン項目を追加したい
- エラー時の挙動を自由に定義したい
このように、Spring Security ログイン画面を自由に制御することは、実践的な開発では欠かせないスキルです。
2. Spring Securityのログインページのデフォルト仕様について
Spring Securityをプロジェクトに追加した場合、特別な設定をしなくても、次のような自動生成されたログインページが表示されます。このログイン画面は、/loginというパスでアクセスでき、フォームにはユーザー名とパスワードの入力欄だけが表示されます。
しかし、この自動生成画面には以下のような制限があります:
- デザインや色のカスタマイズができない
- 追加の入力項目(例:チェックボックスやラベルなど)が追加できない
- エラーメッセージや多言語対応ができない
このような背景から、カスタムログインページ 作成のニーズが生まれます。自動生成画面は開発の初期段階では便利ですが、本番環境では実用的ではありません。
では、実際にどのようにこのデフォルト動作を上書きし、自分だけのログイン画面を作っていくのか。次回の記事では、設定ファイルとHTMLファイルを組み合わせた実装方法を解説していきます。
以下は、デフォルト状態でSpring Securityが提供するフォームの例です(自分で作るわけではありませんが、参考になります):
<form action="/login" method="post">
<div>
<label>Username: <input type="text" name="username"/></label>
</div>
<div>
<label>Password: <input type="password" name="password"/></label>
</div>
<div>
<button type="submit">Sign in</button>
</div>
</form>
このように、HTMLベースのログインページは最終的に自作することになります。次回は、Spring Security 設定ファイルを編集して、ログインページをオリジナルに切り替える方法を見ていきましょう。
3. Spring Securityの設定ファイルの作成(ログインページのURL指定)
それでは実際に、カスタムログインページ 作成の第一歩として、Spring Security 設定ファイルを編集していきましょう。ここでは、ログイン画面を自作したHTMLに差し替えるために、SecurityConfigという設定クラスを作成します。
設定ファイルでは、デフォルトの/loginエンドポイントを無効にし、自分で用意したログインHTMLファイルを使用するようにURLを指定します。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/css/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login") // カスタムログインページのURL
.loginProcessingUrl("/authenticate") // 認証処理を担当するURL
.defaultSuccessUrl("/home") // ログイン成功時の遷移先
.failureUrl("/login?error") // ログイン失敗時のURL
.permitAll()
)
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
}
このSecurityConfigクラスでは、ログインフォームの表示に使うURLを/loginに固定しつつ、ログイン処理自体は/authenticateに分けています。これにより、ログイン画面 HTML作成との連携が明確になり、より柔軟な設計が可能になります。
4. ログインページのHTMLテンプレートを作成する
次に、上記設定で指定した/loginに対応する、ログインページのHTMLファイルを作成します。Spring BootでThymeleafを使っている場合は、テンプレートファイルをsrc/main/resources/templates/login.htmlに配置します。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ログイン</title>
</head>
<body>
<h2>ログイン画面</h2>
<form th:action="@{/authenticate}" method="post">
<div>
<label>ユーザー名:</label>
<input type="text" name="username" />
</div>
<div>
<label>パスワード:</label>
<input type="password" name="password" />
</div>
<div>
<button type="submit">ログイン</button>
</div>
<div th:if="${param.error}">
<p style="color:red;">ユーザー名またはパスワードが間違っています。</p>
</div>
<div th:if="${param.logout}">
<p style="color:green;">ログアウトしました。</p>
</div>
</form>
</body>
</html>
このテンプレートは、Spring Securityの設定ファイルで指定したloginProcessingUrl(ここでは/authenticate)へPOST送信するフォームです。フォーム項目のname属性には、usernameとpasswordを指定する必要があります。これはSpring Securityが自動的に認識するためです。
また、ログイン画面 HTML作成において重要なのは、エラーやログアウトなどの表示です。上記のように、param.errorやparam.logoutを使うことで、状態に応じたメッセージを表示できます。
5. ログインエラーやログアウト後の表示のカスタマイズ
ログインフォームが完成したら、次に考えるべきは「失敗したとき」や「ログアウトしたあと」の表示です。ログインエラー 表示を工夫することで、ユーザーに優しい画面を提供できます。
すでに紹介したHTMLテンプレートの中では、URLのクエリパラメータに応じてエラーやログアウト完了のメッセージを表示するようにしています。たとえば、ログインに失敗したときは自動的に/login?errorにリダイレクトされるため、th:if="${param.error}"でエラーを表示できます。
このような仕組みは、Spring Security 設定ファイルで以下のように記述されているために動作します:
.formLogin(form -> form
.loginPage("/login")
.failureUrl("/login?error") // エラー時のリダイレクト先
)
.logout(logout -> logout
.logoutSuccessUrl("/login?logout") // ログアウト成功時の遷移先
)
この設定によって、ログインエラーが起きたとき、または正常にログアウトしたときに、URLのパラメータを利用してユーザーへメッセージを表示できるようになります。
もちろん、より高度な表示(例えば「残り○回でアカウントロックされます」など)を実現するには、認証イベントを監視するカスタムクラスを用意することも可能ですが、まずはparam.errorやparam.logoutの利用が基本です。
ここまでできれば、カスタムログインページ 作成は実用的なレベルに到達しています。次回は、認証処理の仕組みや、ユーザー情報の取得とログイン後の制御について掘り下げていきます。
6. ログイン後の遷移先を変更する方法
ユーザーがログインに成功したあと、どのページに遷移させるかをコントロールできるのも、ログイン後 遷移先 設定の重要なポイントです。デフォルトでは/(ルート)に遷移しますが、実務ではダッシュボードやユーザー専用ページに自動遷移させたい場面が多くあります。
その場合は、Spring Securityの設定ファイルでdefaultSuccessUrl()を指定します。以下のように設定すれば、ログイン成功後に/homeへ遷移できます。
.formLogin(form -> form
.loginPage("/login")
.loginProcessingUrl("/authenticate")
.defaultSuccessUrl("/home", true) // 成功後に常に遷移
)
trueを渡すことで、以前にアクセスしていたページがあっても、それを無視して常に/homeにリダイレクトする設定になります。
また、ログイン前にアクセスしようとしていたページに戻したい場合はfalseにします。この違いは、ユーザー体験に大きく影響するため、アプリケーションの用途に応じて設計しましょう。
7. セキュリティ面での注意点(パスワードの保存、CSRF対策)
ログイン画面のカスタマイズができるようになったら、次に気をつけたいのがSpring セキュリティ対策です。特に重要なのは、パスワードの保存方法とCSRF対策です。
パスワードの保存方法
Spring Securityでは、ユーザー情報を扱う際にPasswordEncoderを使って、パスワードをハッシュ化して保存するのが常識です。プレーンテキストで保存してはいけません。
以下はBCryptPasswordEncoderを使ってパスワードをハッシュ化する設定例です:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
ユーザー登録時には、下記のようにエンコード処理を行ってからデータベースに保存します:
String rawPassword = "userPassword";
String encodedPassword = passwordEncoder.encode(rawPassword);
これにより、もしデータベースが外部に漏れたとしても、簡単には中身が解読されません。パスワードの保存はアプリケーションの信頼性に直結するため、絶対に暗号化して保管しましょう。
CSRF対策
CSRF(クロスサイトリクエストフォージェリ)は、ユーザーが意図しないリクエストを送信させられる攻撃手法です。Spring SecurityではCSRF保護がデフォルトで有効になっています。
ログインフォームにもCSRFトークンを含めることで、このリスクに備えます。Thymeleafで書いたフォームに次の記述を追加します:
<form th:action="@{/authenticate}" method="post" th:object="${user}">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
</form>
この_csrfはSpring側で自動的に提供されるオブジェクトで、トークンはセッションと紐づいています。トークンが一致しないリクエストは拒否される仕組みです。
なお、APIや認証方式によってはCSRF対策を無効にした方が安全な場合もありますが、通常のフォームログインでは有効化しておくべきです。
8. 開発現場での実践的な使い方やカスタマイズのヒント
最後に、ログイン画面 カスタマイズを行う上で、実際の開発現場でよく使われるテクニックやヒントをいくつか紹介します。
ログイン画面の多言語対応
エラーメッセージやラベルを日本語だけでなく、英語や他言語にも対応させたい場合は、Springのメッセージリソース機能を活用します。messages.propertiesに下記のようなキーを定義しておき、Thymeleafで使用します。
login.username=ユーザー名
login.password=パスワード
login.error=ユーザー名またはパスワードが違います
<label th:text="#{login.username}"></label>
この方法により、国際化対応がしやすくなります。
ログイン後のロールごとの遷移
ユーザーに管理者と一般利用者がいるようなケースでは、ログイン後 遷移先 設定をロールによって分けたい場合もあります。そのときは、AuthenticationSuccessHandlerを独自実装して、ログイン後のリダイレクト先を切り替えます。
@Component
public class CustomSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority auth : authorities) {
if ("ROLE_ADMIN".equals(auth.getAuthority())) {
response.sendRedirect("/admin/dashboard");
return;
}
}
response.sendRedirect("/home");
}
}
このような柔軟な設計ができることで、カスタムログインページ 作成はさらに実践的なものになります。