TIL&WIL

2023-07-26 TIL (RequestDispatcher)

blues_jun 2023. 7. 26. 21:33

오늘 공부한 내용

  • 프로그래머스 알고리즘 문제풀이
  • 내배캠 강의
  • 내일배움캠프 플러스 주차 과제 (회원가입, 로그인 기능 추가)

알게된 내용

나는 로그인 기능을 UsernamePasswordAuthenticationFilter를 상속받는 JwtAuthenticationFilter에서 구현했다.

 

처음 필터를 배울 때에는 컨트롤러 앞단에서 기능을 수행하기 때문에 서로 소통을 할 수 없는줄 알고 있었고, 로그인 성공과 실패를 프론트를 구현해야 확인할 수 있는 줄 알았다.

 

그래도 과제의 결과물 때문에 성공과 실패를 알려줘야해서 처음에는 HttpServletResponse의 sendRedirect() 메서드를 활용해서 로그인이 실패했다는 것을 컨트롤러에 반환했다.

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.getWriter().write("로그인에 실패했습니다.");

        response.sendRedirect("/api/user/login/fail"); // 로그인이 실패했다는 것을 컨트롤러에 반환하기 위해서 사용
    }
    @GetMapping("/user/login/fail")
    public ResponseEntity<ApiResponseDto> failLogin() {
        ApiResponseDto apiResponseDto = new ApiResponseDto("로그인에 실패했습니다. 아이디 및 비밀번호를 확인해주세요.", HttpStatus.UNAUTHORIZED.value());
        return new ResponseEntity<>(
                apiResponseDto,
                HttpStatus.UNAUTHORIZED
        );
    }

여기서 문제점은 필터에서 status를 설정해도 정보가 컨트롤러에 넘어가지 않는다. 

response.sendRedirect()를 호출하면, 브라우저는 지정된 경로로 다시 요청을 보내기 때문에 컨트롤러로 직접 실패 정보를 전달할 수 없는 것이다.

 

여러 정보를 찾아보다가 필터에서 컨트롤러에 실패 정보를 전달하기 위해서는 RequestDispatcher를 사용해야 한다고 했다.

 

RequestDispatcher

  • RequestDispatcher은 현재 요청과 응답을 유지한 채로 다른 서블릿이나 JSP로 디스패치 한다.
  • 즉, 컨트롤러에 실패정보를 전달하기 위해서는 RequestDispatcher를 이용해서 컨트롤러로 포워딩하는 방식을 사용하면 된다.
    //로그인이 실패하는 경우 호출되는 메서드
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        request.setAttribute("message", "로그인에 실패했습니다. 아이디와 비밀번호를 확인 해주세요.");
        
        RequestDispatcher dispatcher = request.getRequestDispatcher("/api/user/login/fail");
        dispatcher.forward(request, response);
    }
    @PostMapping("/user/login/fail")
    public ResponseEntity<ApiResponseDto> loginFail(HttpServletRequest request) {
        String errorMessage = (String) request.getAttribute("message");

        ApiResponseDto apiResponseDto = new ApiResponseDto(errorMessage, HttpStatus.UNAUTHORIZED.value());

        // 상태 코드와 에러 메시지를 ResponseEntity에 담아서 반환
        return new ResponseEntity<>(
                apiResponseDto,
                HttpStatus.UNAUTHORIZED
        );
    }

포스트맨 확인 결과는

원하는 결과가 나왔다.

 

이 방법이 좋은 방법인지는 모르겠지만 일단 원하던 결과에 맞게 구현이 되어서 다행이다..

더 많이 공부하자