프로젝트/뉴스피드

[Spring boot + thymeleaf] 화면단 연결 고군분투기

writtenbyrla 2024. 2. 18. 18:56

 

++ Spring Security와 Jwt를 곁들인...

 

기본적인 api 구현을 끝내고 회원가입, 로그인 화면단 연결을 목표로 타임리프를 이용하여 프론트 작업을 하였으나 로그인 후 페이지 이동시 403 Forbidden 오류로 이 작업을 이틀정도 핸들링했다.

 

ajax나 fetch를 이용한 javascript 문법 미숙으로 인한 오류인 줄은 알고 있었으나 거기에 더해 토큰을 운용하는 과정에서 클라이언트단과 서버단에서 헤더, 쿠키방식을 혼용했기때문에 발생한 대참사였다.

 

사실 react와 같은 프레임워크를 이용하여 클라이언트단 서버를 분리하면 route를 이용해서 리다이렉션을 처리할 수 있을텐데, 템플릿 엔진 + rest api 방식을 이용하다보니 페이지 넘김에 있어서 꼬이고 꼬였고 프로젝트를 한번 엎고 다시 시작하면서 토큰 인증 방식을 변경하여 더욱 꼬였던 것이다.

 

이 문제를 해결하면서 토큰 운용 방식과 시큐리티 적용에 대해 고민하고, 서버와 클라이언트단에서 응답과 요청을 주고받을 때 흐름을 분석해볼 수 있었다.

 

같은 실수를 반복하지 않기 위해 남겨보는 핸들링 기록

 

 


 

 

 

문제 상황 - 환경


[서버] jwt, security 이용

  • 로그인 성공 시 jwt 토큰(accessToken)을 헤더에 추가
  • 인증 필터: request에서 헤더에 있는 토큰 뽑아옴
    → 로그인 후 페이지 이동시 authorizationHeader부터 null값으로 로그가 찍힘
  • 기능 구현은 RestController, 페이지 이동은 일반 Controller 이용

[뷰] 템플릿 엔진 이용하여 tymeleaf, javascript(ajax)로 구현

  • 로그인 성공 시 응답받은 jwt 토큰(accessToken)을 쿠키에 저장, 헤더에 담음
  • 로그인 후 메인페이지 이동: window.location.href=”/home” api 호출
    → 브라우저에서 403 forbidden 오류

 

 

 

문제 상황 - 테스트


1. [로그인 버튼 클릭시]

   1) 로그인 api → 200 ok, response headers에 토큰 응답 받은 것 브라우저에서 확인 가능

   2) 클라이언트단에서 쿠키에 토큰값 저장한 것 확인 가능

 

 

2. [home 페이지 이동시] 403 에러

   1) 처음에는 단순 403 Forbidden 오류

 

   2) 로그인 후 응답받은 토큰값을 다시 담아 넘기기 위해 ajax를 이중으로 처리

     2-1) 개발자 도구 Network에서 home에 대한 처리가 2개로 나눠서 보임

     2-2) 하나는 200 ok로 request header에 토큰값이 있음

     2-3) 다른 하나는 403 forbidden으로 request header에 토큰값이 없음

 

 

 

원인 분석


1. 서버단에서는 헤더로만 토큰 인증을 하고 있음

   → 클라이언트단에서 쿠키를 담아 사용하려면 쿠키 인증 방식으로 수정해야 함

   →  쿠키방식이나 헤더 방식을 하나로 통일하는 것이 가장 좋음, 혼용해서 사용하려다 문제

 

2. 클라이언트단에서 로그인 성공 후, 서버단에서 응답받은 토큰을 다시 헤더에 담아 페이지 이동하는 과정에서 브라우저 이동이 이중으로 처리되어 하나는 200 OK, 다른 하나는 403 Forbidden이 발생

  → 이중처리 불가

  → window.location.href의 경우 브라우저상의 눈에 보이는 화면을 바꿔주는 것이라 여기서 다 처리하려고 하지말고

  → 단순 페이지 이동은 SecurityConfig에서 허용한 후 필요한 정보만 클라이언트단에서 script로 처리

 

 

 

시도 및 해결 방법


1. 로그인 성공 후 응답을 받자마자 다시 헤더에 토큰을 담아 페이지 이동 api 호출 → 실패

 

2. 토큰 운용 방식, 시큐리티 허용 범위 설정 수정 성공!

   1) JwtAuthenticationFilter에서 토큰 인증 시 header에 담긴 토큰이 null값이라면 쿠키에서 받아와서 인증하도록 수정

   2) SecurityConfig에서 메인페이지 이동 api는 permitAll 지정 후 클라이언트단에서 thymeleaf-security 연동하여 인증된 사용자에게만 로그아웃 버튼이 활성화되도록 수정

 

포인트는 [ Security에 대한 근본적인 접근 방식 변경 ] !!

반드시 모든 페이지가 인증된 사용자에게만 보이도록 해야할 필요가 있을까? 페이지 접근 방식을 바꾸었다. 사실 내가 사용자 입장에서 웹 사이트를 이용해보면 그렇지 않은데 왜 나는 모든 것을 인증된 사용자에게만 보이려고 했을까? 라는 의문이 들었다. 시큐리티도 필요할 때 적절하게 사용할 줄 알아야 한다.

 

 


 

리팩토링 후 테스트 결과

 

 

그 결과 로그인 후 메인페이지 이동 시 로그인한 유저의 username이 메뉴 옆에 노출되고, 로그아웃 버튼이 활성화 된다.

 

로그인하지 않고 메인페이지 이동시에는 username과 로그아웃 버튼이 비활성화되는 것을 아주 잘 확인할 수 있다!