iPark Project
보완 필요 부분
- 내가 진행하고 있는 프로젝트에서 로그인은
JWT
를 통해 하고 있다.
- 프로젝트를 진행하던 도중 아래와 같은 문제가 발생했다.
- access token이 만료되면 사용자 정보가 바로 undefined가 된다.
- 브라우저를 사용하다 종료하면 JWT 관련 정보가 local storage에 전부 그대로 남아있다.
(로그아웃을 하지 않고 껐을 경우)
refresh token을 활용한 access token 갱신
- 지금까지 access token이 만료되면
refresh token을 활용해 갱신
할 수 있다는 것은 알고 있었다. 하지만 활용은 하지 않았었다.
- 기껏해야 시연 잠시하고 말고 발표 때 잠깐 보여주고 말고 하기도 했고, 만료 시간을 두둑하게 주면 프로젝트를 진행하면서도 전혀 문제가 없기 때문이었다.
- 하지만 이번에는 실제 사용자들이 우리 프로젝트를 평가하게 되면서 access token 갱신의 필요성을 크게 느꼈다.
- 거두절미하고 코드부터 보자.
function refreshToken() {
const payload = JSON.parse(localStorage.getItem("payload"));
if (payload.exp > (Date.now() / 1000)) {
return;
} else {
const requestRefreshToken = async (url) => {
const response = await fetch(url, {
headers: {
"Content-Type": "application/json"
},
method: "POST",
body: JSON.stringify({
"refresh": localStorage.getItem("refresh")
})
}
);
return response.json();
};
requestRefreshToken(`${backendBaseUrl}user/api/token/refresh/`).then((data) => {
const accessToken = data.access;
localStorage.setItem("access", accessToken);
});
}
};
refreshToken()
- 해당 코드의 포인트는
payload의 exp
즉 만료시간을 활용하는 것이다.
- 만료시간이 지나게 되면 사용자는 바로
undefined
가 되기 때문에 만료 시간을 확인해가면서 사용자가 정의되지 않기 전에 갱신을 해주는 것이다.
- 아직 완성본이 아니라 아래의 문제점이 존재한다.
- 사용자가 사용하다가 갑자기
undefined
가 된다.
- 운좋게 페이지 이동이라도 있다면 전혀 사용자가 눈치 못챌 것이지만 그렇지 않다면
새로고침
을 해야 한다.
- 토큰이 갱신되면서 다시 본인의 정보를 바로 불러올 수 있지만, 이 과정을
자동화
하고 싶다.
브라우저 종료 시 JWT 관련 값 전부 삭제
- JWT를 사용하면서 발급받는
refresh, access, payload
값들은 전부 local storage
에 저장되게 된다.
local storage
는
브라우저 내에 존재
하는 저장소로써, 웹 브라우저가 종료되면 사라지는 SessionStorage 와는 다르게 브라우저가 종료되어도 저장된 정보가 계속 남아있는 공간
이다.
- 즉, 사용자가 로그아웃을 시도해
refresh, access, payload
값들을 삭제하지 않고 끈다면 계속 이 값이 남아있게 된다.
- 여기서 문제가 발생했다.
- 바로 이어서 사용하면 별 문제가 없겠지만, 몇 시간 뒤 혹은 다음 날 등 access token의 만료시간이 지나고 사용하게 된다면 또다시 사용자는
undefined
가 되어 버린다.
- 물론 해당 문제는 로그인이 필요한 부분에서만 일어난다. 나의 경우 로그인이 필요한 부분에서 저런 메세지가 나온다면 로그인을 시도하겠지만(다른 서비스에서도), 아닌 사람도 있을테니 그냥 local starage를 브라우저가 꺼지면 아예 비워버리기로 했다.
첫 번째 시도
- index.html은 우리 프로젝트의 메인 페이지이다. 테스트를 위해 해당 html 아래 쪽에 script를 만들어 아래와 같이 작성해 보았다.
<script>
window.addEventListener("unload", deleteToken)
function deleteToken() {
localStorage.removeItem("payload")
localStorage.removeItem("access")
localStorage.removeItem("refresh")
}
</script>
unload
를 통해 창이 닫히면 local storage를 완전히 비워주었다.
- 맨 처음 index.html에 들어갔을 때 모든 값들이 삭제되어있었고, 이제 된 줄 알고 자려했다.
- 그런데 혹시나 하는 마음에 로그인을 해야 사용 가능한
즐겨찾기 페이지
로 들어갔다.
- 역시나
undefined
였다.
- 이유는 간단했다. index.html을 빠져 나가 다른 페이지로 이동한 것이기 때문에 당연히 local storage가 비워진 것이다.
두 번째 시도
var closing_window = false;
$(window).on('focus', function () {
closing_window = false;
});
$(window).on('blur', function () {
closing_window = true;
if (!document.hidden) {
closing_window = false;
}
$(window).on('resize', function (e) {
closing_window = false;
});
$(window).off('resize');
});
$('html').on('mouseleave', function () {
closing_window = true;
});
$('html').on('mouseenter', function () {
closing_window = false;
});
$(document).on('keydown', function (e) {
if (e.keyCode == 91 || e.keyCode == 18) {
closing_window = false;
}
if (e.keyCode == 116 || (e.ctrlKey && e.keyCode == 82)) {
closing_window = false;
}
});
$(document).on("click", "a", function () {
closing_window = false;
});
$(document).on("click", "button", function () {
closing_window = false;
});
$(document).on("submit", "form", function () {
closing_window = false;
});
var toDoWhenClosing = function () {
localStorage.removeItem("payload")
localStorage.removeItem("access")
localStorage.removeItem("refresh")
return;
};
window.addEventListener("unload", function (e) {
if (closing_window) {
toDoWhenClosing();
}
});
- 브라우저가 닫히는 데
정말 종료하시겠습니까?
라는 메세지는 현재 나에게 필요하지 않기 때문에 그대로 unload
를 사용했다.
- 중요한 포인트는
페이지 간 이동
에 대해 조건을 다 달아주어 페이지를 위에 작성된 방법으로 이동하게 되면 local storage가 비워지지 않는다는 점이다.