발행일

로그인이 계속 풀려서 조건을 바꿨다 — 원인은 setState 바로 다음 줄에 있었다

로그인이 계속 풀려서 조건을 바꿨다

이 글은 2026년 9월에 당시 커밋 이력을 다시 보며 정리한 것입니다. 날짜는 작업한 날 기준입니다.

2020년 11월, 대학 4학년 종합설계로 홈트레이닝 웹 큐피트를 만들고 있었습니다. 편입하고 처음 해 보는 팀 프로젝트였고, 프런트는 거의 제가 맡았어요. 로그인·회원가입·마이페이지·마일리지 화면이 제 몫이었습니다.

11월 14일 밤에 마일리지 화면을 붙였습니다. 로그인하면 마일리지 버튼이 생기고, 누르면 "○○님의 마일은 ○○ 마일 입니다"가 뜨는 화면이에요. 그런데 로그인을 했는데도 버튼을 누르면 "로그인 해주세요" 가 뜨고 로그인 화면으로 튕겼습니다. 다시 로그인해도 같았어요.

새벽 2시의 수정

11월 15일 02:05 커밋(fb6790c)의 제목이 "로그인이 계속 풀려서 다르게 처리"입니다. 바뀐 건 Mileage.js 네 줄이에요.

-                else {
+                //로그인이 계속 풀리는 문제가 생겨서 이렇게 처리 함
+                else if (!this.state.userid) {
                     alert("로그인 해주세요")
                     window.location.href="/login"
                 }

마일리지 응답이 없으면 무조건 로그인 화면으로 보내던 걸, userid 쿠키까지 없을 때만 보내게 바꿨습니다. userid는 쿠키에 살아 있었으니 이제 메시지는 안 뜹니다. 마일리지 값도 안 뜨지만요.

그날 확인한 건 거기까지였습니다. "로그인 해주세요"가 안 뜨니 고쳐진 걸로 봤어요.

원인은 로그인 화면에 있었다

이 글을 쓰려고 Login.js를 다시 열었습니다. 11월 11일 첫 커밋(517f3e0)부터 저장소의 마지막 커밋까지, 필드 이름은 바뀌었지만 이 순서는 그대로예요.

if (response.data.login === "True") {
    this.setState({
        token: response.data.token,
        userid: response.data.userid,
        level: response.data.level,
        login: response.data.login
    })
    // ... expires 계산
    cookie.save("userid", this.state.userid, cookieOptions);
    cookie.save("token", this.state.token, cookieOptions);

setState를 부르고 바로 다음 줄에서 this.state.token을 읽어 쿠키에 넣습니다. 클래스 컴포넌트의 setState는 이 자리에서 바로 반영되지 않으니, 저장되는 건 초기값인 빈 문자열이에요. 토큰 쿠키가 늘 비어 있었던 겁니다.

그런데 userid는 살아남았습니다. 로그인 폼에 입력한 값이 이미 this.state.userid에 들어 있었으니까요. 그래서 "로그인은 된 것 같은데 마일리지만 안 되는" 모양이 됐습니다. 마일리지 화면은 Authorization 헤더에 그 빈 토큰을 실어 보냈고, 서버가 마일리지를 안 주니 else로 떨어졌어요.

정리하면 로그인이 풀린 게 아니라 처음부터 토큰이 저장된 적이 없었습니다. 제가 바꾼 조건은 그 사실을 화면에서만 가렸어요.

같은 자리를 세 번 만졌다

커밋을 시간순으로 보면 그날 밤 Mileage.js를 세 번 고쳤습니다.

시각커밋바뀐 것
11/14 23:36014920e "마일리지 1차"요청에 Authorization 헤더 추가, else if(!this.state.userid) 분기
11/14 23:59de1bda3 "마일리지 2차"요청을 클릭 핸들러에서 생성자로 옮기고 분기를 else
11/15 02:05fb6790c다시 else if (!this.state.userid), 주석 추가

1차에 있던 조건을 2차에서 없앴다가 3차에서 되돌린 거예요. 그 사이에 토큰이 왜 없는지는 한 번도 안 봤습니다. 요청이 언제 나가는지(클릭 때인지 화면 열릴 때인지)를 바꾸는 데 시간을 썼어요.

곁가지로, 쿠키 옵션에 httponly: false를 적어 뒀는데 브라우저 자바스크립트로 심는 쿠키에 그 옵션은 의미가 없고, react-cookiereact-cookies가 둘 다 설치돼 있었습니다. 쿠키를 읽고 쓰는 코드는 전부 react-cookies였고, react-cookieindex.js에서 앱을 감싸는 CookiesProvider 한 줄에만 쓰였어요. 그 Provider가 없어도 react-cookies는 동작하니 사실상 껍데기였습니다.

검증

그날 확인한 것:

  • 로그인 뒤 마일리지 버튼을 눌러 "로그인 해주세요"가 안 뜨는 것. 마일리지 값이 비어 있는 건 그대로였습니다.

이 글을 쓰며 git show로 확인한 것:

  • Login.jssetState 직후 this.state.token 읽기가 첫 커밋(517f3e0)부터 저장소 마지막 커밋(7fc0343, 11/22)까지 그대로인 것.
  • Mileage.js가 11/14~15 세 커밋에서 분기를 else ifelseelse if로 오간 것.
  • package.jsonreact-cookie·react-cookies가 같이 있고, 소스에서 import되는 건 react-cookies뿐인 것.
  • 2023년 12월에 쓴 이력서에는 이 프로젝트를 "프런트 전담, 담당은 회원 관리·마이페이지·로그인·로그아웃·식단 조절·운동 페이지·옷 페이지"로 적었는데, 저장소에서 그 파일들의 저자가 전부 저인 것과 맞습니다. 다만 이력서는 개발 인원을 프런트 1명이라 적었고, 저장소에는 다른 팀원의 커밋이 46개 있어요(홈 화면 파일을 GitHub 웹에서 지우고 다시 올린 42개와 4개). 코드를 쓴 사람과 올린 사람이 갈린 흔적입니다.

남은 것 · 한계

  • 토큰이 실제로 비어 있었는지는 코드로 추론한 것입니다. 당시 브라우저에서 쿠키를 열어 본 기록이 없어요. setState의 동작과 코드 순서로 보면 빈 값이 저장됐다고 보는 게 맞지만, 서버가 토큰 없이도 마일리지를 줬을 가능성까지는 확인할 수 없습니다.
  • 고치지 않았습니다. 저장소 마지막 커밋까지 Login.js는 같은 모양이에요. 발표까지 마일리지 화면이 어떻게 동작했는지는 커밋에 남아 있지 않습니다.
  • 이 유형은 그 뒤로도 반복됐습니다. 2024년 TripTune에서는 마운트된 적 없는 훅이 401을 처리하고 있었고, 2026년에야 로그인 풀림의 계보를 401 처리 한 곳으로 모으면서 원인부터 보게 됐어요. 증상을 조건으로 덮은 첫 기록이 이 커밋입니다.

관련 글: 큐피트 — 대학 졸업작품으로 만든 홈트레이닝 웹 · Next.js 안에 react-router-dom이 두 달 있었다 · 로그인이 자꾸 풀리던 서비스 — 401 처리를 한곳으로 모으기까지 · 카테고리 하나에 폴더 하나 — 복붙 열한 벌