스프링 시큐리티와 연계하여 로그인에 실패했을 경우 로그인화면으로 리다이렉트 시키면서 이메일을 다시 입력폼에 유지하려고 여러가지 시도를 해봤다.

스프링 시큐리티에서 로그인 실패를 담당하는 인터페이스는 AuthenticationFailureHandler 이다.

public interface AuthenticationFailureHandler {
 
/**
 * Called when an authentication attempt fails.
 * @param request the request during which the authentication attempt occurred.
 * @param response the response.
 * @param exception the exception which was thrown to reject the authentication
 * request.
 */
void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException exception)
throws IOExceptionServletException;
}

위의 형태를 가지는 간단한 인터페이스로, 스프링 시큐리티 설정에서 formLogin() 에 설정하면 로그인이 실패했을 떄 호출되며 이에 대한 처리를 수행한다.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .anyRequest().authenticated()
        // form 로그인 
        .and()
        .formLogin()
        .loginPage("/login").permitAll()
        .usernameParameter(USERNAME_PARAMETER)
        .passwordParameter(PASSWORD_PARAMETER)
        .successHandler(authenticationSuccessHandler()) (1)
        .failureHandler(authenticationFailureHandler()) (2)
}
 
// 생략 
@Bean
AuthenticationSuccessHandler authenticationSuccessHandler() {
    return new HoneymonUserAuthenticationSuccessHandler();
}
 
@Bean
AuthenticationFailureHandler authenticationFailureHandler() {
    return new HoneymonUserAuthenticationFailureHandler();
}
로그인 성공시 후속처리
로그인 실패시 후속처리

그리고 HoneymonUserAuthenticationFailureHandler가 호출되면 /login?error={message}&email={email}의 형식으로 리다이렉트되도록 해뒀다. 그런데 암만 로그인 실패가 나도 /login?error= 로 리다이렉트 되지를 않는 것이다. 이 문제 떄문에 한참 씨름을 했다.

public class HoneymonUserAuthenticationFailureHandler implements AuthenticationFailureHandler {
 
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOExceptionServletException {
        if(exception instanceof BadCredentialsException) {
            exception = new BadCredentialsException("security.exception.bad_credentials");
        }
        response.sendRedirect("/login?error=" + exception.getMessage() + "&email=" + request.getParameter(USERNAME_PARAMETER));
    }
}

옆에 누군가가 봐줬으면 참 좋았을텐데…​

그러다가 정말 우연찮게

'아, 내가 LoginWeb' 클래스를 지우고 ViewController 로 처리하도록 했지?

하는 생각이 미쳤다. 리다이렉트가 되지 않고 있는 url에 대해서는 다음과 같이 설정되어 있었다.

@Configuration
public class WebConfig  extends WebMvcConfigurerAdapter {
  @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("front/login");  // 로그인 
        registry.addViewController("/signup").setViewName("front/signup");  // 회원가입 
    }
}

이 간단한 설정이 나를 괴롭혔던 주 원인이었다.

ViewController 에서 /login 요청에 대한 처리를 수행하기는 하지만 뒤에 전달되는 파라미터들을 모두 소거시킨다는 것을 이해하지 못한 것이다.

어떤 장애든지 기본적인 접근은 그 장애에 영향을 주는 설정부터 살펴보도록 하자. ㅡ_-);; 내가 허비한 시간 우짤꺼야!!

This is a shortcut for defining a ParameterizableViewController that immediately forwards to a view when invoked. Use it in static cases when there is no Java controller logic to execute before the view generates the response.



+ Recent posts