분명 로컬 환경에서는 잘 작동하던 서비스가
운영서버에 올리니 거짓말처럼 500 에러가 발생했다.
문제는 로그인 후 원래 보던 페이지로 다시 보내주기 위해 쿠키를 설정해주는 부분에서 발생했다.
public void setCookie(String cookieName, String value) {
if (!value.contains("/member/join")) {
Cookie cookie = cookieUt.createCookie(cookieName, value);
resp.addCookie(cookie);
}
}
@GetMapping("/login")
@PreAuthorize("isAnonymous()")
public String showLogin() {
String referer = rq.getReferer();
rq.setCookie("previousUrl", referer);
return "member/login";
}
이 메서드에서 value 값이 null로 들어와 NullPointerException이 난 것이었다.
자체 로그인과 oauth2 로그인에서 해당 메서드를 사용하고 있었기에 로그인 요청만 들어오면 500 에러가 나버렸다.
왜 null 값이 들어오는지 삽질만 하염없이 하다가 http 요청 헤더를 뜯어보고 redirect 경로의 프로토콜이 http로 되어 있기 때문에 발생한 문제임을 알 수 있었다.
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendRedirect("/member/login"); // 로그인 페이지 URL로 이동
}
}
위 코드는 인증받지 않은 요청이 들어왔을 때, 로그인 폼으로 리다이렉트 시키는 메서드이다.
response.sendRedirect()는 디폴트 값으로 http 프로토콜을 사용한다고 한다. 때문에 로컬 서버에서는 문제가 없었지만, https를 사용하는 운영서버에서는 문제가 발생한 것이었다!
로그인시 헤더에서 "referer" 헤더 필드의 값을 받아오는데, 프로토콜이 달라지니 null값이 들어가서 NullpointerException이 발생한 것이 원인이었다.
@GetMapping("/login")
@PreAuthorize("isAnonymous()")
public String showLogin() {
String referer = rq.getReferer();
rq.setCookie("previousUrl", referer); <<- 이부분. 문제.
return "member/login";
}
public String getReferer() {
String referer = req.getHeader("referer");
if (referer != null) {
int queryIndex = referer.indexOf("?");
if (queryIndex != -1) {
referer = referer.substring(0, queryIndex);
}
}
return referer;
}
이를 해결하기 위해 sendRedirection() 설정을 절대 경로(http) 대신 이전 페이지와 동일한 프로토콜을 사용하는 상대 경로로 바꾸면 되겠다고 생각했고,
절대 경로를 상대 경로로 바꿔주는 use-relative-redirects 설정을 true로 설정하여 해결했다.
application.yml에 아래와 같이 설정을 해줬더니 성공적으로 작동했다.
server:
port: 8080
tomcat:
use-relative-redirects: true