UserDetails (2/4)
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를 파라미터로 주입받아 사용