요즘 앱에서는 자동로그인 기능을 사용하기보단 앱을 설치하여 로그인하면 자동로그인과 같이 매 접속시마다 로그인이 유지된 상태를 가지고 일정 기간이 지나면 다시 로그인하도록 하는 구조로 되어있습니다. 하지만 회사 요구사항에서 앱 기능에 자동로그인이 있어서 해당 기능을 구현하게 됐어요. 웹기반 하이브리드앱을 만들며 깨달은 JWT가 눈에 아른거리는 경험을 간단히 적어보려고 합니다!
처음에 리서치할땐 스프링 시큐리티에서 자동로그인 관련 기능을 제공해주는 것을 알고 있었기 때문에 막연히 간단히 해당 기능을 구현하여 금방 끝날 업무리고 생각했어요.
SecurityConfig에서 간단히 RememberMe기능만 아래처럼 활성화시켜주면 되는데요. 이 기능을 통해 remember-me 토큰을 발급받아 쿠키에 담아 클라이언트에게 보내줍니다. 해당 토큰은 개발자가 정해주는 시간 (디폴트 2주)까지 지속적으로 로그인을 유지시켜주는 역할을 합니다. 즉 말그대로 Remember Me인 것이죠. (자동로그인 기능을 해외에서는 remember-me 기능 이라고 부르나봐요)
@Override
protected void configure(HttpSecurity http) throws Exception {
http
/* ...다른 설정들 생략... */
.and()
.rememberMe()
/* ... 생략...*/
그래서 저는 이 기능을 활용해서 자동로그인 버튼을 사용자가 on/off함에 따라 해당 토큰을 발급한 쿠키를 생성하여 응답하거나 삭제하도록하면 된다고 생각했어요. 그래서 아래 기존의 TokenBasedRememberMeService 코드를 보시면 setCookie()에서 remember-me쿠키를 생성해주는 부분을 찾을 수 있는데 해당 부분을 참고하여 커스텀으로 필요한 부분만 뽑아서 아래와 같이 만들었어요
이건 세션쿠키가 아니기 때문에 브라우저를 종료하고 다시 실행하면 쿠키가 남아있는 것을 확인 할수 있어요. 잘 작동했습니다.
그런데 웹에서 정상적으로 작동하는 것을 확인했지만 나~중에 앱 패키징을 외주맡기며 안드로이드 앱에서 정상 작동하지 않는 것을 발견했어요. 어쩔땐 작동하고 어쩔땐 작동하지 않았는데요. 사실 프로그램이라는 게 코드가 적혀있는대로 한줄한줄 실행되는건데 어쩔땐 되고 어쩔땐 안된다? 엄청 이상하지 않나요?
원인은 쿠키/세션을 처리해주는 앱자체의 특징에 있었는데요. 이 링크에 보니까 제가 겪은 부분이랑 똑같은 현상을 묘사하고 있었습니다. 실제로 앱이 할당받는 램과 전체쿠키가 보관되어지는 로컬스토리지간에 동기화가 제대로 안이루어져있어서 그렇다고 해요. 또는 모바일 특성상 잦은 ip변경으로 쿠키 동기화가 되지 않아 그런 일도 생긴다고 합니다.
따라서 동기화처리를 해주면되는데 해당 부분은 "웹뷰 쿠키 동기화"라고 검색하면 많은 참고자료를 찾아볼 수 있습니다. 하지만 앱개발자가 아니라 직접 해결하기는 어려운 부분이라 외주 개발자님이 해당 부분을 봐주셨는데요, 개선이 된건지 안된건지 웹뷰의 쿠키 상태를 확인할수없어서 잘 모르겠지만 이상하게 또 로그아웃을 하거나 세션을 invalidate시켜주어도 다시 접속하면 세션이 남아있는 걸 볼수 있었습니다.
계속 이메일을 통해 커뮤니케이션을 해서인지 진행속도가 느려 더이상 쿠키 동기화 부분에 대해 신경쓰지 않고 백엔드에서 해결해줄 수 있는 방법을 찾았습니다. 또 다른 업무도 있었기 때문에 더 이상 쿠키를 동기화하는 문제로 시간을 끌수는 없는 상황이었구요.
그래서 앱을 실행할때마다 유효한 사용자인지 직접 체크해주도록 했어요. 앱에서는 실행할때마다 디바이스 아이디를 담아 각 사용자에 맞도록 저장 및 업데이트하는 API를 백엔드로 호출하도록 하고 해당 회원의 자동로그인 상태에 따라 메인페이지나 로그인페이지로 리다이렉트 시켜주도록 했습니다. 이렇게 하니까 간단해보이긴 하는데, 간단한만큼 어떤 사이드 이펙트가 있을 것 같긴한데 아직 생각이 나진 않네요.
그런데 생각해보니 애초에 세션기반인증이 아니라 토큰기반인증을 사용했으면 이런 불필요한 고민을 할필요다 없다는 생각이 들었는데요.
세션은 지속적으로 요청이 올때마다 서버에서 인증된 유효한 사용자인지 해당 세션에 대해 검사를 해야하기 때문에 따로 저장소에 세션들을 저장해두어야합니다.
이같이 저장소를 두고 해당 사용자를 검사한다는 것은 멀티플랫폼 환경에서 치명적인 단점으로 작용합니다. 한 사용자의 모든 디바이스들의 세션을 동기화해줘야하는 문제가 생기기때문입니다. 뿐만 아니라, 사실 단순히 현재 안드로이드앱만 만들고 있는 중에도 이렇게 애를 써야하는 거면 상당히 골칫거리라고 할수있겠죠.
세션기반인증은 이런 단점외에도 사용자가 많아짐에따라 서버를 스케일아웃하게 되면 서버간 세션을 계속해서 동기화해주어야하기 때문에 또 문제가 생겨버립니다. 해결 방법은 당연히 있겠지만 이번 자동로그인을 개발하면서 인증/인가를 세션으로 하는 것에 굉장히 회의적으로 바뀌었어요.
세션과 달리 JWT를 사용하면 동기화할 필요없이 서버에서 독립적으로 디코딩/복호화만 하여 사용자를 인증해주는 것이기 때문에 동기화에 대한 걱정이 필요없습니디. 즉 통신이 stateless 하기때문에 플랫폼 독립적인 동시에 세션을 동기화해주는 것과 전혀 무관하게 stateful한 상태를 가질수 있습니다.
하지만 제 경우에는 이미 개발은 다 진행이 된상태였기때문에 세션기반에서 토큰기반으로 변경하려면 변경포인트가 많아져 시간이 오래걸려 앱을 처음실행시 고유기기 id를 기준으로 해당 유저를 찾아 자동로그인 상태를 체크하고 그때 인가된 세션을 만들어주기로 해주고 메인페이지 혹은 로그인페이지로 리다이렉트시켜주기로 했습니다. 그리고 매 접속시마다 됐다 안됐다하는 동기화이슈를 가지지 않기 위해 세션을 초기화했어요.
'기술과 생각 > HTTP 일반' 카테고리의 다른 글
Cookie vs Session vs JWT (0) | 2022.02.23 |
---|