Next.js 카카오 로그인 구현하기 (w spring) (2)

moreas·2023년 4월 17일
1

팀 프로젝트

목록 보기
7/14
post-thumbnail

🔥 로그인 유지

고민

로그인 유지를 어떤 방식으로 해줄 것인가?에 대하여 고민이 많았다.
로그인된 유저의 정보를 헤더 컴포넌트에 띄워 페이지 이동 시에도 로그인 상태를 유지하려고 했다.
그러기 위해 일단 리턴값으로 온 토큰을 쿠키에 저장하여 사용할 수 있도록 했다. (react cookies 라이브러리를 사용했다.)

        const response = await axios.get(`/oauth/token?code=${code}`, {
          withCredentials: true,
        });
        const { accessToken } = response.data;
        cookie.save("accessToken", accessToken, {
          path: "/",
        });
        dispatch(setToken(accessToken));

필요한 컴포넌트에서 로그인 정보 요청하기

헤더 컴포넌트에서는 쿠키에 저장된 토큰을 헤더에 담아보내면서 로그인 정보를 요청했고 리덕스에 저장한 후 컴포넌트에서 사용하려고 해봤다.
그런데 수많은 undefined를 만났다.

유지하기

  • 리덕스를 사용하여 유저 정보를 저장했기에 리덕스에서 정보를 불러와 컴포넌트에 띄우려고 했다. 보여지기는 했지만 새로고침을 해도 유지가 안됐다. .,,

  • 안해본 방법이 없었다. 미들웨어를 설치해보기도 하고 10버전 이상에서는 사용을 권장하지 않는 getInitialProps를 사용해보기도 했다. 하지만 우리는 클라이언트 단에서 바로 통신을 주고받고 있고 프엔 서버인 api폴더에서 통신을 하고 있는 것이 아니기 때문에 당연히 로직은 적용되지 않고 새로고침하면 헤더의 상태가 풀렸다.

  • 뭔가를 놓치고 있는 게 분명히 있어서 로그인이 아닌 다른 데이터들을 가져올 때 사용하는 로직을 살펴봤다.

  • 설마 하면서 useState를 사용하여 user의 상태를 관리하고 저장하는 로직을 추가하고 받아온 로그인 정보를 setUser에 담았다.
    user에 담긴 닉네임이 존재할 때 헤더에 띄우는 로직을 추가했는데 새로고침을 해도 유지가 되었다. 거의 일주일이 넘는 삽질 끝에 해결을 했다.
    이게 완벽한 정답은 아닌 것 같지만 가장 기본적인 방법을 시도도 안해보다니..ㅠㅜ 허탈했다.

  • 유저가 있다면 이미지, 닉네임과 로그아웃 버튼을 보여주고 유저가 없다면 로그인 버튼을 보여주도록 작성했다.

 const [user, setUser] = useState<User[]>([]);

// setUser에  로그인 정보 담고,
// 닉네임과 이미지 꺼내서 헤더에서 보여주기

 {!user ? (
          <>
            <button
              id="login-btn"
              className={styles["login-btn"]}
              onClick={handleOpenLoginModal}
            >
              로그인
            </button>
          </>
        ) : (
          <>
              <Image
                className={styles["kakao-profile-img"]}
                src={user.imgUrl}
                alt="카카오프로필"
                width={45}
                height={45}
              />
              반가워요, {user.nickName}! 
            <button
              id="login-btn"
              className={styles["login-btn"]}
              onClick={handleLogout}
            >
              로그아웃
            </button>
          </>
        )}

+ accessToken 삭제하여 자동 로그아웃하기

  • 현재 refreshToken으로 silent하게 로그인을 유지하는 방법은 적용하지 못했다. ㅠ
  • 따라서 토큰 만료 전, 일정 시간이 지나면 쿠키에 저장된 토큰을 삭제하고 로그아웃 상태를 만든 후, 유저에게 다시 로그인을 하도록 하는 방법을 선택했다.

토큰 삭제 hook 생성

  • setTimeout 을 사용하여 타이머를 만들고 일정시간이 지나면 자동 로그아웃을 하는 로직을 생성한다.
function useDeleteToken() {
  const dispatch = useDispatch();
  useEffect(() => {
    const deleteToken = () => {
      cookie.remove("accessToken", { path: "/" });
      dispatch(resetToken());
    };

    const timer = setTimeout(deleteToken, 1 * 60 * 1000); // 임의로 시간을 1분으로 설정했다. 

    return () => {
      clearTimeout(timer); 
    };
  }, []);
}

적용하기

  • 공통적인 상태를 담고 있는 헤더에서 해당 훅을 적용해주었다.
  • 일정 시간이 지나면 쿠키와 리덕스에 저장된 토큰과 로그인 정보를 삭제하고 로그아웃 상태로 만들어 로그인 버튼을 띄운다. 동시에 메인 페이지로 이동한다.
  • 해당 시간이 지나자 자동으로 헤더에 로그아웃이 적용되고 로그인 버튼을 띄운다.

🌎 CORS 에러

  • 프론트와 백 서버가 분리되어 있다면 여기서 악명높은 CORS 에러를 만날 수 있다.
  • 백엔드에서 관련 설정을 마쳤다고 해도 해결이 안되는 경우가 있어서 프론트에서도 조치를 취해야 할 경우가 있다.
  • next.js 에서는 rewrites 설정을 통하여 백엔드 서버를 연결할 수 있다.

// next.config.js

const nextConfig = {
  async rewrites() {
    return [
       {
       source: "/:path*",
         destination: "http://localhost:8080/:path*",
      },
    ];
  },
};

module.exports = nextConfig;
  • 로컬호스트8080 주소 뒤에 오는 모든 경로에 대해 연결할 수 있도록 설정해주었다. 그러나 이렇게 모든 경로로 연결을 해버리면 404를 만나거나 에러가 날 때 백엔드 서버로 페이지가 연결되니 주의하자.
  • 이렇게 설정을 해주면 백엔드 서버와 통신할 수 있다.

회고

어려웠던 점

  • 소셜 로그인... 생각보다 어려웠다. 로그인 완료? 끝! 하고 끝나는 게 아니라 이후 HOC도 설정이 필요하고 경로에 대한 보호 조치도 필요했는데 그 부분을 제대로 짚고 넘아가지 못해서 아쉬운 부분이 많다.
  • 상당 부분 반복되는 axios 인스턴스를 미리 로직으로 지정해볼 수 있을 것 같다.
  • 로그인에 관한 로직은 설계도 중요하고 생각보다 어려운 과정이기에 공부가 더 필요하다고 느꼈다.

얻은 것

  • 무수히 많은 코드를 고치고 살펴보고.. 이런 적이 있나 싶게 짧은 시간 안에 비동기 통신에 대해 경험해봐서 유익했다.
  • oauth2와 관련하여 인증과 인가에 대해 공부할 수 있는 경험이었다.
  • 백엔드와의 소통에서 부족함을 많이 느꼈다. 프론트 지식만 알기보다 전반적인 로그인 흐름에 대해 공부하고 백엔드와 뜻깊은 경험이었다. 팀프로젝트가 아니었으면 실무에서 어려움을 겪었을 텐데 미리 경험해볼 수 있어서 커뮤니케이션이나 어려운 점에 대해 짚고 넘어갈 수 있는 대비가 되었다.
profile
Everything is connected 🐶 좀 더 나은 개발을 위해

0개의 댓글