vuex + js-cookie를 이용한 로그인 관리

은승균·2022년 3월 21일
0

학부생 인턴을 하면서 회사에서 VueJS를 이용하여 쇼핑몰을 만들고 있다.
가장 기본이 되는 유저의 로그인 관리를 하면서 구현한 내용을 정리해두려고 한다.
가장 기본이 되는 인증 관리 구현이지만, 모종의 이유로 백엔드에서 쿠키과 세션을 사용하지 않고, accessToken과 refreshToken만을 이용한다.

자세한 상황을 설명하긴 좀 애매한데, 아무튼 구글링 해서 찾을 수 있는 기본적인 세션과 토큰을 이용한 로그인 관리 예제를 따르지 않으며, 서버에서 토큰만을 주고 프론트에서 관리하도록 구현해야한다.
대표님 살려주세요..

Vuex

Vuex란?

Vuex는 Vue.js 애플리케이션을 위한 상태관리패턴 + 라이브러리 이다. 중앙의 store에 상태를 저장해두고 Vue 애플리케이션의 모든 곳에서 접근할 수 있다.
Vuex 상태는 예측 가능한 방식으로만 변경될 수 있도록 한다.

Vuex를 사용하는 이유

Vuex를 사용하는 가장 큰 이유는 상태 관리와 데이터의 움직임을 예측가능하도록 하여 한 눈에 볼 수 있도록 하기 위함이다.

이렇게 할 수 있는 기본적인 원리는 Flux 패턴에서 창안된 단방향 데이터 흐름의 개발 패턴덕분이라고 할 수 있다.

Flux 패턴은 MVC 패턴의 양방향 데이터 흐름으로 인한 복잡성을 해결한 단방향 데이터 흐름의 개발 패턴이다.

Vuex Store 사이클

  • actions
    • API 호출과 같은 비동기 작업을 수행한다.
    • actions에서 mutations을 호출하여 state를 변경할 수 있다.
  • mutations
    • state를 변경할 수 있는 메소드 이다.
    • 동기적으로 수행된다.
  • state
    • Vue 컴포넌트에서의 data에 해당한다.
    • vuex에서는 state를 mutations을 통해서만 변경하는 것을 권장한다.
  • getter
    • Vue 컴포넌트에서의 computed 처럼 어떠한 계산된 값을 return 한다.
    • state의 변경이 반영되어 view에 업데이트 된다.

유저 정보 저장

로그인 이후 API로부터 받아온 응답에 User에 관한 정보를 Vuex에 저장하여 활용하려고 하였다.
그 중에 API요청 시에 header에 포함되어 전송되는 access_token을 저장하여 활요하려고 하였다. 하지만 vuex에 저장된 상태는 브라우저를 새로고침하거나 종료하면 유지 되지 못하고 삭제되는 문제가 발생한다.

이러한 문제를 해결하기 위한 것이 vuex-persistedstate라는 라이브러리이다.
이 라이브러리는 vuex에 저장된 state를 자동으로 로컬 스토리지와 연결시켜주고 업데이트를 해주면서 관리를 해준다.

모든 Vuex state를 로컬 스토리지와 연동하면 로컬 스토리지로부터 값을 불러오고 저장하는 일이 빈번히 일어나게되어 속도 저하 문제가 발생할 수 있다.

이를 해결하기 위해 원하는 vuex module만을 persisted state로 설정하여 활용한다.

	import { createStore } from 'vuex';
    import createPersistedState from 'vuex-persistedstate';

    import user from './modules/user';
    import access_token from './modules/access_token';

    export default createStore({
        state: {
          ...
        },
        mutations: {
          ...
        },
        actions: {
          ...
        },
        getters: {
          ...
        },
        modules: {
            user,
            access_token,
            ...
        },
        plugins: [
            createPersistedState({
                paths: ['access_token'],
            })
        ],
    });

내가 진행하고 있는 프로젝트에서는 user와 access_token을 vuex store 모듈로 분리하여 사용하고 있다.
규모가 커질 수록 vuex를 관리하는 것에 어려움이 생기게 되고 이를 각 module로 분리하여 활용하면 조금 더 관리하기 용이하다.

access_token을 persistedstate에 저장하는 것의 문제점

위에서 설명한 것처럼 vuex-persistedstate는 localStorage를 활용한다. 즉, 브라우저 애플리케이션 저장소에 보관이 된다는 것인데, 자동 로그인의 경우 문제 없이 구현할 수 있었지만 일반적인 로그인 상황에서는 약간의 문제가 발생했다. 브라우저를 종료했을 때에 로그아웃이 되어야하지만, 현재 상황에서는 로그아웃이 되지 않는다.

또한 localStorage에 token을 저장하게 된다면 다른 사람이 같은 디바이스를 사용하면 토큰을 탈취할 수도 있기 때문에 좋지 않다고 생각한다. 다만 자동 로그인의 유저의 동의를 받고 디바이스에 저장을 하기 때문에 해당 위험을 감수하고 localStorage를 이용한다.

시도 1. sessionStorage

이러한 문제를 해결하기 위해 세션 스토리지를 사용했다.
하지만 sessionStorage에 저장된 데이터는 세션 당 컨테이너가 생성된다. 즉, 세션이 탭간 공유되지 않아 새 탭을 열어 사이트를 들어가면 로그인이 되어있지 않는 것을 확인할 수 있었다.

기본적으로 쿠키는 브라우저에 저장이 되어 만료되기 전까지 http 요청 시마다 헤더에 포함되어 날아가게 된다. 쿠키는 도메인 별로 설정할 수 있으며 브라우저에 저장이 되기 때문에 다른 탭을 이용하여 사이트에 접속해도 같은 쿠키에 접근할 수 있었다.

vue-cookie, vue-cookies 등의 라이브러리가 있었지만, 굳이 사용하지 않아도 js-cookie 라이브러리로 충분히 사용할 수 있었다.

Vuex + js-cookie 를 이용한 로그인 관리

여전히 액세스 토큰은 Vuex store에 저장되어야 하며, 새로고침을 해도 값을 유지할 수 있어야한다.
Cookie로부터 사용하는 컴포넌트에 바로 가져올 수도 있을 것이라고 생각했지만, Vuex를 통한 상태관리로 얻을 수 있는 관리의 이점을 생각하여 Vuex에 쿠키 사용을 추가하는 방식으로 구현하였다.

	import { createStore } from 'vuex';
    import createPersistedState from 'vuex-persistedstate';

    import user from './modules/user';
    import access_token from './modules/access_token';

    export default createStore({
        state: {
          ...
        },
        mutations: {
          ...
        },
        actions: {
          ...
        },
        getters: {
          ...
        },
        modules: {
            user,
            access_token,
            ...
        },
        plugins: [
            createPersistedState({
			paths: ['access_token'],
			storage: {
				getItem(key) {
					if (JSON.parse(localStorage.getItem('saveLogin'))) {
						return localStorage.getItem(key);
					} else {
						return Cookies.get(key);
						// return sessionStorage.getItem(key);
					}
				},
				setItem(key, value) {
					if (JSON.parse(localStorage.getItem('saveLogin'))) {
						localStorage.setItem(key, value);
					} else {
						Cookies.set(key, value);
						// sessionStorage.setItem(key, value);
					}
				},
				removeItem(key) {
					if (JSON.parse(localStorage.getItem('saveLogin'))) {
						localStorage.removeItem(key);
					} else {
						Cookies.get(key);
						// sessionStorage.removeItem(key);
					}
				},
			},
		}),
        ],
    });

Vuex plugin 부분에 vuex-persistedstate의 custom storage를 구현하는 코드이다.
getItem은 vuex로부터 값을 가져올 때 처리되는 로직을 포함하고, setItem과 removeItem은 비슷한 방식으로 값을 저장하고 삭제할 때의 커스텀 로직을 추가할 수 있다.

로그인 시에 자동 로그인 유무를 saveLogin에 저장을 해두고 해당 값에 따라 로컬 스토리지로부터 accessToken을 저장하고 가져올지, Cookie로부터 값을 저장하고 가져올지 결정하도록 하였다.

Cookie의 사용의 문제점

이로써 자동 로그인과 일반적인 로그인을 구현할 수 있었다.
다만 쿠키는 매 전송 시마다 무조건 요청과 함께 전송되는데, 실제로 서버에서 쿠키로부터 값을 읽지 않아 쓸데없이 쿠키의 데이터가 실려 전송된다는 오버헤드가 존재하지만 현재 내가 진행중인 프로젝트의 상황에서는 이게 최선일 것 같다..

profile
3대 500을 향해서

0개의 댓글