시리즈 안내

이 문서는 UserDetails와 GrantedAuthority 이후의 내용입니다.

로그인 성공 후 어떤 동작을 할지 커스터마이징하는 방법을 다룹니다.


1. AuthenticationSuccessHandler란?

Spring Security는 로그인 성공 후 기본적으로 특정 페이지로 리다이렉트합니다. 하지만 REST API에서는 리다이렉트 대신 JSON 응답을 내려줘야 합니다.

AuthenticationSuccessHandler 는 로그인 성공 시 어떤 동작을 할지 정의하는 인터페이스입니다. 직접 구현해서 원하는 응답을 만들 수 있습니다.

구현해야 하는 메서드는 단 하나입니다:

void onAuthenticationSuccess(
    HttpServletRequest request,
    HttpServletResponse response,
    Authentication authentication
) throws IOException, ServletException;
  • request : 클라이언트의 HTTP 요청 정보 (IP, 헤더 등)
  • response : 서버가 클라이언트에게 보낼 응답 객체
  • authentication : 인증된 사용자 정보 (username, authorities 등)

2. super를 호출하면 안 되는 이유

AuthenticationSuccessHandler인터페이스입니다. 인터페이스를 구현(implements)한 클래스에서는 super를 호출할 수 없습니다.

[실수] super.onAuthenticationSuccess() 호출 불가

```java

// 컴파일 에러

super.onAuthenticationSuccess(request, response, authentication);

```

인터페이스에는 구현체가 없으므로 super로 올라갈 부모가 없습니다.

SimpleUrlAuthenticationSuccessHandler를 상속(extends)했다면 super 호출이 가능하지만, 인터페이스 구현 시에는 직접 응답을 작성해야 합니다.


3. REST API에서의 구현 방법

로그인 성공 시 JSON을 응답으로 내려주면 됩니다.

@Override
public void onAuthenticationSuccess(
        HttpServletRequest request,
        HttpServletResponse response,
        Authentication authentication) throws IOException, ServletException {

    HttpSession session = request.getSession();
    String username = authentication.getName();
    String ipAddress = getClientIP(request);
    String userAgent = request.getHeader("User-Agent");
    Instant now = Instant.now();

    session.setAttribute("LOGIN_TIME", now);
    session.setAttribute("LOGIN_IP", ipAddress);
    session.setAttribute("USER_AGENT", userAgent);

    response.setStatus(HttpServletResponse.SC_OK);
    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");
    response.getWriter().write("{\"username\":\"" + username + "\"}");
}
  • response.setStatus(HttpServletResponse.SC_OK) : HTTP 200 상태 코드 설정
  • response.setContentType("application/json") : 응답 타입을 JSON으로 지정
  • response.setCharacterEncoding("UTF-8") : 한글 깨짐 방지
  • response.getWriter().write(...) : 응답 본문에 JSON 문자열 직접 작성
  • authentication.getName() : 인증된 사용자의 username 반환

4. HTTP 헤더 이름은 표준 규약

request.getHeader()에 넣는 문자열은 HTTP 표준(RFC 7231)에서 정의된 헤더 이름입니다. 정확한 이름을 모르면 null이 반환됩니다.

자주 쓰는 헤더 이름:

헤더 이름용도
User-Agent클라이언트 브라우저/앱 정보
X-Forwarded-For프록시를 거친 실제 클라이언트 IP
Authorization인증 토큰
Content-Type요청 본문 타입

5. SecurityConfig에 등록하는 방법

구현한 핸들러를 Spring Security 설정에 연결해야 적용됩니다.

@Bean
public SecurityFilterChain securityFilterChain(
        HttpSecurity http,
        LoginSuccessHandler loginSuccessHandler) throws Exception {

    http
        .formLogin(form -> form
            .successHandler(loginSuccessHandler)
        );

    return http.build();
}
  • successHandler(loginSuccessHandler) : 로그인 성공 시 실행할 핸들러 등록
  • @Component로 등록된 LoginSuccessHandler를 파라미터로 주입받아 사용