実現したいこと
Spring Boot 3.0.8とSpring Security6を使用してログイン処理失敗時に、エラーメッセージを画面に表示させたい。かつ、画面更新時にはそのエラーメッセージがなくなっているようにしたい。
発生している問題・エラーメッセージ
※下記はユーザー名は正しいがパスワードが間違った入力の場合のコンソール出力です。
コンソールを見ると/login-errorにPOSTリクエストが来た後に、/loginにリダイレクトされてしまい結果、画面にエラーメッセージが表示されずじまいといった形になってしまいます。
o.s.security.web.FilterChainProxy : Securing POST /login o.s.s.a.dao.DaoAuthenticationProvider : Failed to authenticate since password does not match stored value o.s.security.web.FilterChainProxy : Securing POST /login-error s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.controllers.RootController#onAuthenticationErrorPost(AuthenticationException, Model) s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.controllers.RootController#onAuthenticationErrorPost(AuthenticationException, Model) s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.controllers.RootController#onAuthenticationErrorPost(AuthenticationException, Model) o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext o.s.s.web.DefaultRedirectStrategy : Redirecting to http://localhost:18080/login o.s.security.web.FilterChainProxy : Securing GET /login o.s.security.web.FilterChainProxy : Secured GET /login o.s.web.servlet.DispatcherServlet : GET "/login", parameters={} s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.crewsync.controllers.RootController#login() o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, application/xhtml+xml, image/avif, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8, application/signed-exchange;v=b3;q=0.7] o.s.web.servlet.DispatcherServlet : Completed 200 OK
該当のソースコード
SecurityConfig.java
1package com.example.conf; 2 3import org.springframework.boot.autoconfigure.security.servlet.PathRequest; 4import org.springframework.context.annotation.Bean; 5import org.springframework.context.annotation.Configuration; 6import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 7import org.springframework.security.config.annotation.web.builders.HttpSecurity; 8import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 9import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 10import org.springframework.security.crypto.password.PasswordEncoder; 11import org.springframework.security.web.SecurityFilterChain; 12import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler; 13 14/** 15 * Spring Security設定クラスです 16 */ 17@Configuration 18@EnableWebSecurity 19@EnableMethodSecurity 20public class SecurityConfig { 21 22 @Bean 23 public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 24 http.formLogin(login -> login 25 .loginPage("/login") 26 .loginProcessingUrl("/login") 27 .defaultSuccessUrl("/") 28 .failureHandler(new ForwardAuthenticationFailureHandler("/login-error")) 29 .usernameParameter("email") 30 .passwordParameter("password") 31 .permitAll()) 32 .logout(logout -> logout 33 .logoutSuccessUrl("/login") 34 .invalidateHttpSession(true) 35 .deleteCookies("JSESSIONID")) 36 .authorizeHttpRequests(authz -> authz 37 .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() 38 .requestMatchers("/img/**").permitAll() 39 .requestMatchers("/").permitAll() 40 .requestMatchers("/register").permitAll() 41 .anyRequest().authenticated()); 42 return http.build(); 43 } 44 45 @Bean 46 public PasswordEncoder passwordEncoder() { 47 return new BCryptPasswordEncoder(); 48 } 49} 50
RootController.java
1package com.example.controllers; 2 3import javax.naming.AuthenticationException; 4 5import org.springframework.beans.factory.annotation.Autowired; 6import org.springframework.security.crypto.password.PasswordEncoder; 7import org.springframework.security.web.WebAttributes; 8import org.springframework.stereotype.Controller; 9import org.springframework.ui.Model; 10import org.springframework.web.bind.annotation.GetMapping; 11import org.springframework.web.bind.annotation.ModelAttribute; 12import org.springframework.web.bind.annotation.PostMapping; 13import org.springframework.web.bind.annotation.RequestAttribute; 14import org.springframework.web.bind.annotation.RequestMapping; 15 16import com.example.auth.LoginUser; 17import com.example.controllers.forms.UserRegisterForm; 18import com.example.domains.services.UserRegisterService; 19 20@Controller 21public class RootController { 22 23 private final UserRegisterService userRegisterService; 24 25 private final PasswordEncoder passwordEncoder; 26 27 @Autowired 28 public RootController(UserRegisterService userRegisterService, PasswordEncoder passwordEncoder) { 29 this.userRegisterService = userRegisterService; 30 this.passwordEncoder = passwordEncoder; 31 } 32 33 @GetMapping("/") 34 public String root() { 35 return "index"; 36 } 37 38 @RequestMapping("/login") 39 public String login() { 40 return "login"; 41 } 42 43 @PostMapping("/login-error") 44 public String onAuthenticationErrorPost( 45 @RequestAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) AuthenticationException ex, 46 Model model) { 47 model.addAttribute("loginError", ex); 48 return "login"; 49 } 50 51 @GetMapping("/register") 52 public String signup() { 53 return "signup"; 54 } 55 56 @PostMapping("/register") 57 public String register(@ModelAttribute UserRegisterForm form) { 58 LoginUser user = new LoginUser(); 59 user.setEmail(form.getEmail()); 60 user.setUsername(form.getUsername()); 61 user.setPassword(passwordEncoder.encode(form.getPassword())); 62 userRegisterService.registerUser(user); 63 return "redirect:/login"; 64 } 65}
login.html
1<!DOCTYPE html> 2<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <link 7 href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" 8 rel="stylesheet" 9 integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" 10 crossorigin="anonymous" 11 /> 12 <link rel="stylesheet" href="../static/css/styles.css" th:href="@{/css/styles.css}" /> 13 <title>サインイン</title> 14 </head> 15 <body> 16 <div class="container"> 17 <div class="row justify-content-center"> 18 <form method="post" class="col-lg-4 col-md-8 col-sm-8 col-xs-8" action="index.html" th:action="@{/login}"> 19 <img src="../static/img/logo.png" th:src="@{/img/logo.png}" class="mx-auto d-block my-5" alt="logo.png" /> 20 <div class="card"> 21 <div class="card-body"> 22 <h5 class="card-title text-center login-title">ログイン</h5> 23 <hr /> 24 <div class="form-group mb-3"> 25 <label for="email" class="form-label">メールアドレス</label> 26 <input type="email" class="form-control" id="email" name="email" placeholder="name@example.com" required /> 27 </div> 28 <div class="form-group mb-3"> 29 <label for="password" class="form-label">パスワード</label> 30 <input type="password" class="form-control" id="password" name="password" required /> 31 </div> 32 <div class="my-1" th:if="${loginError}"> 33 <span class="text-danger" th:text="${loginError.message}"></span> 34 </div> 35 <hr /> 36 <div class="d-flex flex-column"> 37 <button type="submit" class="btn btn-primary btn-block mb-3">サインイン</button> 38 <a th:href="@{/register}" class="btn btn-success btn-block">ユーザー登録</a> 39 </div> 40 </div> 41 </div> 42 <input type="hidden" name="_csrf" th:value="${_csrf.token}" /> 43 </form> 44 </div> 45 </div> 46 </body> 47</html> 48
試したこと
色々調べたり、ChatGPTに質問したが解決できなかったため質問させていただきます。
補足情報(FW/ツールのバージョンなど)
Java17
Spring Boot 3.0.8
Spring Security 6.0

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。