spring boot custom login failed 핸들러+thymeleaf 에러메시지 처리방법 - 세션에 에러메시지 담으면 안되는 이유
좋은 소스를 잘 만들기 위해서 하루종일 고심했다.
어떻게 하면 다른 사람이 소스를 보고 최대한 리소스를 덜 사용하고 수정할 수 있을까?
어떤 추가 기능이 오더라도 최대한 영향을 받지 않을 수 있을까?
@Log4j2
@RequiredArgsConstructor
public class CustomLoginFailureHandler implements AuthenticationFailureHandler {
//private static final String ACCOUNT_PERMISSION_URL = "/account/permission";
private static final String ACCOUNT_PERMISSION_URL = "/account/ssonewsign";
@Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException auth) throws IOException, ServletException {
스프링부트에서 위와 같은 커스텀로그인 failure handler가 있었고
아이디 패스워드가 틀릴 경우 리다이렉트 하는 메소드는 아래와 같았다.
private void loginFailRedirect(HttpServletRequest request, HttpServletResponse response,
String location, String errorMsg) throws IOException {
log.info(request.getParameter("memberId") + " - " + errorMsg);
request.getSession().setAttribute("errMsg", errorMsg);
response.sendRedirect(location);
}
그리고 최종적인 html페이지에서 타임리프를 쓴 스크립트는 아래와 같았다.
<script th:inline="javascript">
function loginCheck() {
//const check = [[${session.errorCheck}]];
const errormsg = [[${session.errMsg}]];
if(errormsg){
alert(errormsg);
}
}
loginCheck();
</script>
이소스에는 굉장한 버그가 숨겨져 있다.
로그인 처리를 하고 스프링부트의 로그인실패 핸들러프로세스를 탄 후에 적절하게 세션에 메시지를 담아서 뿌려주는 것이 맞으나
새롭게 페이지를 고치거나
아예 새창을 띄우게 될 경우
기존 세션때문에 아이디,패스워드를 입력하지 않았는데도 오류 메시지를 뿌려준다.
참고로 세션을 이용한 메시지 처리 방식은 별로 선호하지 않는다.
기존 소스가 이런형식으로 되어 있었고 모든 소스가 이런 방식을 따랐을 뿐이다.
내가 만약 설계했다면 에러메시지를 세션값에 담아서 뿌리지 않았을 것이다.
또한 서버에 부하를 줄 가능성이 굉장히 크기 때문에 세션 사용을 지양하고 싶다.
새로고침 했을 경우에 아이디,패스워드 값을 체크해서 값이 있을 경우만 프로세스를 타게 만들더라도 문제가
프론트에서 먼저 아이디,패스워드를 체크 한후에 그 뒤에 java서버에서 세션값을 만들어서 체크를 하기 때문에
첫 화면에서 아이디,패스워드를 검증하는 것을 할 수가 없다.
그렇다고 맨처음 화면을 로딩했을 때 체크하는 변수를 자바스크립트로 선언하더라도 100% 모든 상황에 대해 체크도 할 수가 없게 된다.
에러메시지를 어떤방식으로 뿌려줄 것인지에 대해 설계를 잘못하면 뒤에 개발자들이 개고생하는 것을 보여주는 아주 좋은 예인것 같다.
어떤 방법을 쓰더라도 에러메시지는 절대 세션에 담아서 보내면 문제가 생긴다는 것을 깨닫게 된 좋은 계기다.
그래서 해결 방법은 아주 간단하다.
나는 아주 간단한 해결방법을 좋아하는데
세션타임아웃에 1초를 주면 끝난다.
그러면 처음 에러메시지를 띄어주고 바로 세션이 invalidate하게 된다.
private void loginFailRedirect(HttpServletRequest request, HttpServletResponse response,
String location, String errorMsg) throws IOException {
log.info(request.getParameter("memberId") + " - " + errorMsg);
request.getSession().setMaxInactiveInterval(1);//세션타임아웃 1초
request.getSession().setAttribute("errMsg", errorMsg);
response.sendRedirect(location);
}
<script th:inline="javascript">
function loginCheck() {
//const check = [[${session.errorCheck}]];
const errormsg = [[${session.errMsg}]];
if(errormsg){
alert(errormsg);
}
}
loginCheck();
</script>
기존 소스에서 내가 수정한 부분은 .세션타임아웃을 1초로 준 한줄뿐이다.
한줄로 모든 소스가 아름다워졌다.
끝.