개발 낙서장

[TIL] 내일배움캠프 35일차 - Filter 단에서 발생하는 403 에러 해결 본문

Java/Sparta

[TIL] 내일배움캠프 35일차 - Filter 단에서 발생하는 403 에러 해결

권승준 2024. 2. 14. 22:34

 

 

오늘의 학습 키워드📚

Filter 처리

Filter는 Spring에서 요청이 DispatcherServlet으로 가기 전에, 응답이 사용자에게 전달되기 전에 거치는 거름망 역할을 한다.
즉, 모든 요청과 응답은 반드시 Filter를 거치게 돼있다.
(예외는 있는데 setFilterProcessesUrl을 통해 특정 API 혹은 URL만 해당 Filter를 거치게 할 수 있다. 어쨌든 어떠한 요청이든 Filter를 거치게 돼있다.)

이번 팀 프로젝트를 구현하면서 유저의 인증과 인가 처리를 Filter에서 하기로 했는데 한 가지 문제가 발생했다.
분명 사전에 로그인, 회원가입 등의 API는 접근 권한을 허가를 해줬는데 자꾸 회원가입을 할 때도 403 에러가 발생하는 것이다.

403 에러?

해당 요청에 접근할 권한이 없을 때 발생하는 에러이다. 즉, 접근을 허가해 줬는데도 Filter에서 인가를 시도해 액세스가 거절되는 것이다.

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
        FilterChain filterChain) throws ServletException, IOException {

        String bearerToken = jwtUtil.getJwtFromHeader(req);

        try {
            userDetailsService.validateToken(bearerToken);
        } catch (LoginException e) {
            log.error(e.getMessage());
            return;
        }

        String tokenValue = jwtUtil.getTokenWithoutBearer(bearerToken);

        if (StringUtils.hasText(tokenValue)) {

            if (!jwtUtil.validateToken(tokenValue)) {
                log.error("Token Error");
                return;
            }

            Claims info = jwtUtil.getUserInfoFromToken(tokenValue);

            try {
                setAuthentication(info.getSubject(), tokenValue);
            } catch (Exception e) {
                log.error(e.getMessage());
                return;
            }
        }

        filterChain.doFilter(req, res);
    }

해당 코드에서 계속해서 접근이 제한돼 에러가 발생하는 것이다.
이때만 해도 사전에 url을 permitAll 해주면 해당 URL로 인한 요청은 Filter를 거치지 않는다고 생각했다.

그래서 url 허가 설정도 바꿔보고 다른 부분 주석 처리도 해봤는데 해결이 되지 않았다.

문제는 userDetailsService.validateToken(bearerToken) 이 부분에서 발생했다.
해당 메소드는 Token에 대한 정보를 담고 있는 TokenRepository에서 해당 토큰을 찾아내 만료된 토큰인지 검사하는 메소드이다.
검증되지 않은 토큰(혹은 빈 토큰)으로 검증을 시도하니 자꾸 접근 권한 에러가 발생했던 것이다.

찾아보니 requestMatchers로 permitAll 해주는 것의 의미는 '권한이 없어도 접근을 허가한다'라는 의미였다.
(Filter를 거치지 않는 의미가 아니었다.... 당연한 건데 바보 같은 생각이었다.)

        if (StringUtils.hasText(tokenValue)) {

            if (!jwtUtil.validateToken(tokenValue)) {
                log.error("Token Error");
                return;
            }

            try {
                userDetailsService.validateToken(bearerToken);
            } catch (LoginException e) {
                log.error(e.getMessage());
                return;
            }

            Claims info = jwtUtil.getUserInfoFromToken(tokenValue);

            try {
                setAuthentication(info.getSubject(), tokenValue);
            } catch (Exception e) {
                log.error(e.getMessage());
                return;
            }
        }

그래서 해당 부분을 이렇게 바꿨다. 토큰이 들어왔을 경우 유효한 토큰인지를 검증해야 에러가 발생하지 않았다.

어떻게 생각하면 Filter의 기본만 유의했으면 쉽게 해결될 문제였는데 아예 잘못 알고 있었어서 발생한 트러블이었다.


오늘의 회고💬

팀 프로젝트 구현을 마무리했다. 오랜 시간 공부를 집중한 건 아니었지만 하루 내내 팀원들과 소통하면서 발표 자료를 정리하고 본인들이 한 기능들, 트러블 슈팅을 정리하고 팀원이 부족했던 부분은 알려주고 보완해 주면서 뜻깊은 시간을 가졌던 것 같다.

 

내일의 계획📜

팀 프로젝트 최종 발표와 회고 시간이 있을 예정이다.

Comments