Security 로그인 실패 시, 에러메시지 출력

Woo Yong·2023년 5월 28일
0

Spring

목록 보기
5/15

📌 해결문제

Spring Security적용 후, 로그인 기능을 구현했다. 하지만 로그인 실패 시, 오류 메시지를 출력하려고 했다.

SecurityConfig

	@Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        http.csrf().disable();
        http.authorizeHttpRequests()
                .requestMatchers(
                        new AntPathRequestMatcher("/question/modify/**")).authenticated()
                .requestMatchers(
                        new AntPathRequestMatcher("/question/create**")).authenticated()
                .anyRequest().permitAll()
                .and()
                .formLogin()
                    .loginPage("/loginForm")
                    .loginProcessingUrl("/login")
                    .failureForwardUrl("/loginError")
                    .defaultSuccessUrl("/")
                .and()
                    .logout()
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/");
        return http.build();
    }

로그인 실패 컨트롤러 - loginError

	@PostMapping("/loginError")
    public String loginerror(@Valid LoginForm loginForm, BindingResult bindingResult){
        return "loginForm";
    }

📌 해결과정

위 코드는 로그인 기능을 구현했을 때 코드이다.
로그인을 하기위해서 /loginForm경로로 이동하고, 로그인 처리를 하기 위해서 /login경로로 이동하도록 설정하였다.
따라서 올바른 정보를 입력하면 defaultSuccessUrl의 경로에 맞게 이동하는 걸 확인할 수 있었다.
그리고 잘못된 정보를 입력하면 failureForwardUrl의 경로에 맞게 이동해서 @Valid어노테이션을 이용해서 Username과 Password가 틀린 경우에 맞게 errorMessage를 출력할려고 했다.

위 방법을 구현하기 위해서 UserDetailsService를 구현한 CustomUserDetailsService 코드를 수정하였다.

CustomUserDetailsService

	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SiteUser user = siteUserRepository.findByUsername(username)
                .orElseThrow(() -> {
                    throw new UsernameNotFoundException("해당 사용자를 찾을 수 없습니다.:"+username);
                });
        return new CustomDetails(user);
    }

/login경로 접근 시 호출되는 loadUserByUsername메소드에서 username에 해당하는 SiteUser객체가 없을 경우 UsernameNotFoundException이 발생하도록 작성하였다.
여기서부터 너무 많이 헤매었다... 아무리 재실행하여도 UsernameNotFoundException이 발생하지 않았다... 하지만 디버깅을 통해 확인해보면 orElseThrow가 작동하는 것을 확인했다..
그리고 많은 고민과 구글링을 통해서 해결방법을 찾게되었다...


📌 해결방안

참고자료1, 참고자료2를 보면서 failureHandler메소드를 통해서 로그인 실패 시, 처리과정을 구분할 수 있었던 것이다... 즉, 로그인 실패 시, failureHandler메소드의 처리과정 후 failureForwardUrl의 경로로 이동하는 것이다.
이전에는 failureHandler가 정의 되어있지 않아 일방적으로 실패 url로 이동하여 에러 처리 메시지를 보여주기 어려웠던 것이다.

SecurityConfig의 customAuthFailureHandler

 @Bean
    AuthenticationFailureHandler customAuthFailureHandler(){
        return new CustomAuthFailureHandler();
    }

customAuthFailureHandler의 onAuthenticationFailure메소드

@Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        String errorMessage = null;
        if(exception instanceof BadCredentialsException || exception instanceof InternalAuthenticationServiceException){
            errorMessage = "Username과 Password가 맞지 않습니다. 다시 확인해 주십시오";
        }else if(exception instanceof DisabledException){
            errorMessage = "계정이 비활성화 되었습니다. 관리자에게 문의하세요.";
        }else if(exception instanceof CredentialsExpiredException){
            errorMessage = "비밀번호 유효기간이 만료 되었습니다. 관리자에게 문의하세요.";
        }else{
            errorMessage = "알 수 없는 이유로 로그인에 실패하였습니다. 관리자에게 문의하세요.";
        }
        request.setAttribute("errorMessage", errorMessage);
        request.getRequestDispatcher(DEFAULT_FAIL_URL).forward(request,response);
    }
profile
Back-End Developer

0개의 댓글