Skip to content

Commit

Permalink
[Feat] Oauth 관련 자동 로그아웃 기능 설정
Browse files Browse the repository at this point in the history
- Oauth 로그인 액세스 토큰 만료시간 관려하여 자동 로그아웃 기능 구현
- 코드 가독성이 많이 떨어지는 상황으로 추후 리팩토링 예정

Issues #122
  • Loading branch information
novice1993 committed Sep 21, 2023
1 parent d0bc9d3 commit 7ca217e
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 41 deletions.
19 changes: 9 additions & 10 deletions client/src/components/Logins/EmailLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { setLoginState } from "../../reducer/member/loginSlice";
import { setLogoutState } from "../../reducer/member/loginSlice";
import { useDispatch } from "react-redux";

const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onLogin, onSignup }) => {
const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onSignup }) => {
const titleText = "이메일로 로그인";
const emailLabelText = "이메일";
const passwordLabelText = "비밀번호";
Expand Down Expand Up @@ -43,7 +43,7 @@ const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onLogin, onS
}
};

// 🔴 자옹 로그아웃 테스트
// 🔴 자동 로그아웃 관련 코드 -> 정리 필요
const handleLoginClick = async () => {
try {
const response = await axios.post("http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com:8080/members/login", { email, password }, { validateStatus: (status) => status >= 200 && status < 600 });
Expand All @@ -52,9 +52,9 @@ const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onLogin, onS
const accessToken = response.headers["authorization"];
const refreshToken = response.headers["refresh"];

dispatch(setLoginState());
if (accessToken) sessionStorage.setItem("accessToken", accessToken);
if (refreshToken) sessionStorage.setItem("refreshToken", refreshToken);
dispatch(setLoginState());

const toastStyle = {
fontSize: "15px",
Expand All @@ -63,15 +63,15 @@ const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onLogin, onS
};

// 로그인 유지시긴 알림
toast.warning("로그인 상태는 30분 동안 지속됩니다", {
toast.warning("로그인 상태는 30분 동안 유지됩니다", {
style: toastStyle,
position: "top-center",
});

// 로그아웃 알림 1차 설정 + 이때 시간 저장
const settingTime01 = 1000 * 7; // 10초
const settingTime02 = 1000 * 7; // 10초
const logoutAlarmTime01 = Date.now(); // 소환한 시간
const settingTime01 = 1000 * 60 * 29; // 29분
const settingTime02 = 1000 * 60; // 1분
const logoutAlarmTime01 = Date.now(); // 1차 알람 호출한 시간
sessionStorage.setItem("logoutAlarmTime01", `${logoutAlarmTime01}`); // 세션 스토리지에 저장

setTimeout(() => {
Expand All @@ -84,7 +84,7 @@ const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onLogin, onS
});

// 2차 알람 및 로그아웃 처리 + 토큰 삭제
const logoutAlarmTime02 = Date.now();
const logoutAlarmTime02 = Date.now(); // 2차 알람 호출한 시간
sessionStorage.setItem("logoutAlarmTime02", `${logoutAlarmTime02}`);

setTimeout(() => {
Expand All @@ -102,7 +102,6 @@ const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onLogin, onS
}, settingTime02);
}, settingTime01);

// onLogin();
onClose();
} else {
setGeneralError(response.data.message || JSON.stringify(response.data));
Expand All @@ -115,6 +114,7 @@ const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onLogin, onS
}
}
};
// 🔴 자동 로그아웃 관련 코드 -> 정리 필요

return (
<ModalBackground>
Expand All @@ -141,7 +141,6 @@ export default EmailLoginModal;
// 컴포넌트 props 타입 정의
interface EmailLoginModalProps {
onClose: () => void;
onLogin: () => void;
onSignup: () => void;
}

Expand Down
172 changes: 141 additions & 31 deletions client/src/page/MainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,6 @@ const MainPage = () => {

const [isLoginConfirmationModalOpen, setLoginConfirmationModalOpen] = useState(false);

const handleLogin = () => {
closeEmailLoginModal();
setLoginConfirmationModalOpen(true);
dispatch(setLoginState());
};

const handleLoginConfirmationClose = () => {
setLoginConfirmationModalOpen(false);
};
Expand All @@ -143,7 +137,7 @@ const MainPage = () => {
setSelectedMenu(menu);
};

// 🔴🔴 페이지 로드 시 로컬 스토리지의 토큰을 기반으로 로그인 상태를 확인합니다.
// 🔴 자동 로그아웃 관련 코드 -> 정리 필요
useEffect(() => {
const acessToken = sessionStorage.getItem("accessToken");
if (acessToken !== null) {
Expand All @@ -158,11 +152,14 @@ const MainPage = () => {

// 1) 현재시간
const currentTime = Date.now();
const settingTime01 = 1000 * 7; // 10초
const settingTime02 = 1000 * 7; // 10초
const settingTime01 = 1000 * 60 * 29; // 29분
const settingTime02 = 1000 * 60; // 1분

// 2) 첫번째 알람 타이머가 아직 있다면
// 로그인 알람 설정한 시간 (세선 스토리지에 저장 되어있음)
const logoutAlarmTime01 = sessionStorage.getItem("logoutAlarmTime01");
const logoutAlarmTime02 = sessionStorage.getItem("logoutAlarmTime02");

// 2) 첫번째 알람 타이머가 아직 있다면
if (logoutAlarmTime01 !== null) {
// 3) 비동기 설정 시간 - 새로고침 전까지 지나간 시간
const timeGone = currentTime - parseInt(logoutAlarmTime01);
Expand All @@ -177,7 +174,7 @@ const MainPage = () => {
position: "top-center",
});

// 2차 알람 및 로그아웃 처리 + 토큰 삭제
// 2차 알람 세팅
const logoutAlarmTime02 = Date.now();
sessionStorage.setItem("logoutAlarmTime02", `${logoutAlarmTime02}`);

Expand All @@ -193,50 +190,163 @@ const MainPage = () => {
style: toastStyle,
position: "top-center",
});
}, 7000);
}, settingTime02);
}, remainTime);
}

// 3) 두번째 알람 타이머가 아직 있다면
const logoutAlarmTime02 = sessionStorage.getItem("logoutAlarmTime02");
if (logoutAlarmTime02 !== null) {
const timeGone = currentTime - parseInt(logoutAlarmTime02);
const remainTime = settingTime02 - timeGone;
// 3) 첫번째 타이머 실행 후 -> 두번째 타이머 설정했는데 새로고침 시
if (logoutAlarmTime02 !== null) {
const timeGone = currentTime - parseInt(logoutAlarmTime02);
const remainTime = settingTime02 - timeGone;

setTimeout(() => {
// 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제
sessionStorage.removeItem("logoutAlarmTime02");
setTimeout(() => {
// 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제
sessionStorage.removeItem("logoutAlarmTime02");

dispatch(setLogoutState());
sessionStorage.removeItem("accessToken");
sessionStorage.removeItem("refreshToken");
dispatch(setLogoutState());
sessionStorage.removeItem("accessToken");
sessionStorage.removeItem("refreshToken");

toast.warning("로그아웃 처리되었습니다", {
style: toastStyle,
position: "top-center",
});
}, remainTime);
}
toast.warning("로그아웃 처리되었습니다", {
style: toastStyle,
position: "top-center",
});
}, remainTime);
}
}
}, []);

// Oauth 로그인 관련 코드
useEffect(() => {
// MainPage로 돌아왔을 때 url에 prameter가 있다면 -> url을 따서
const urlParams = new URLSearchParams(window.location.search);
const accessToken = urlParams.get("access_token");
const refreshToken = urlParams.get("refresh_token");

// 세션 스토리지에 저장 + 로그인 처리를 한다
if (accessToken && refreshToken) {
sessionStorage.setItem("accessToken", `Bearer ${accessToken}`);
sessionStorage.setItem("refreshToken", refreshToken);
dispatch(setLoginState());
// Remove access_token and refresh_token from the URL

// url에 있는 파라미터를 지운다
urlParams.delete("access_token");
urlParams.delete("refresh_token");
window.history.replaceState({}, "", "?" + urlParams.toString());

window.location.reload();

// 🔴 자동 로그아웃 테스트
// 현재 시간, 알림 세팅 타임, 세션 스토리지에 저장된 타이머 시간
const currentTime = Date.now();
const settingTime01 = 1000 * 60 * 29; // 29분
const settingTime02 = 1000 * 60; // 1분
const logoutAlarmTime01 = sessionStorage.getItem("logoutAlarmTime01");
const logoutAlarmTime02 = sessionStorage.getItem("logoutAlarmTime02");

const toastStyle = {
fontSize: "15px",
fontWeight: 350,
color: "black",
};

// ✅ 1차 타이머도 설정되지 않았다면 -> 최초 설정 시
if (logoutAlarmTime01 === null) {
toast.warning("로그인 상태는 30분 동안 유지됩니다", {
style: toastStyle,
position: "top-center",
});

// 1차 타이머 저장
const logoutAlarmTime01 = Date.now(); // 1차 알람 호출한 시간
sessionStorage.setItem("logoutAlarmTime01", `${logoutAlarmTime01}`); // 세션 스토리지에 저장

setTimeout(() => {
// 첫번째 알람 실행되었으므로 -> 첫번째 시간기록 삭제
sessionStorage.removeItem("logoutAlarmTime01");

toast.warning("1분 뒤 로그아웃 처리됩니다", {
style: toastStyle,
position: "top-center",
});

// 2차 알람 및 로그아웃 처리 + 토큰 삭제
const logoutAlarmTime02 = Date.now(); // 2차 알람 호출한 시간
sessionStorage.setItem("logoutAlarmTime02", `${logoutAlarmTime02}`);

setTimeout(() => {
// 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제
sessionStorage.removeItem("logoutAlarmTime02");

dispatch(setLogoutState());
sessionStorage.removeItem("accessToken");
sessionStorage.removeItem("refreshToken");

toast.warning("로그아웃 처리되었습니다", {
style: toastStyle,
position: "top-center",
});
}, settingTime02);
}, settingTime01);
}

// ✅ 1차 타이머는 설정 됐는데 -> 새로고침 시
if (logoutAlarmTime01 !== null) {
// 3) 비동기 설정 시간 - 새로고침 전까지 지나간 시간
const timeGone = currentTime - parseInt(logoutAlarmTime01);
const remainTime = settingTime01 - timeGone;

setTimeout(() => {
// 첫번째 알람 실행되었으므로 -> 첫번째 시간기록 삭제
sessionStorage.removeItem("logoutAlarmTime01");

toast.warning("1분 뒤 로그아웃 처리됩니다", {
style: toastStyle,
position: "top-center",
});

// 2차 알람설정
const logoutAlarmTime02 = Date.now();
sessionStorage.setItem("logoutAlarmTime02", `${logoutAlarmTime02}`);

setTimeout(() => {
// 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제
sessionStorage.removeItem("logoutAlarmTime02");

dispatch(setLogoutState());
sessionStorage.removeItem("accessToken");
sessionStorage.removeItem("refreshToken");

toast.warning("로그아웃 처리되었습니다", {
style: toastStyle,
position: "top-center",
});
}, settingTime02);
}, remainTime);
}

// ✅ 두번째 타이머 설정 됐는데 -> 새로고침 시
if (logoutAlarmTime02 !== null) {
const timeGone = currentTime - parseInt(logoutAlarmTime02);
const remainTime = settingTime02 - timeGone;

setTimeout(() => {
// 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제
sessionStorage.removeItem("logoutAlarmTime02");

dispatch(setLogoutState());
sessionStorage.removeItem("accessToken");
sessionStorage.removeItem("refreshToken");

toast.warning("로그아웃 처리되었습니다", {
style: toastStyle,
position: "top-center",
});
}, remainTime);
}
}
}, []);
// 🔴 자동 로그아웃 관련 코드 -> 정리 필요

const [isGuideModalOpen, setGuideModalOpen] = useState(false);

Expand All @@ -263,7 +373,7 @@ const MainPage = () => {
<OAuthLoginModal onClose={closeOAuthModal} onEmailLoginClick={openEmailLoginModal} onEmailSignupClick={openEmailSignupModal} onWatchListClick={() => handleMenuChange("관심종목")} onHoldingsClick={() => handleMenuChange("보유종목")} />
)}

{isEmailLoginModalOpen && <EmailLoginModal onClose={closeEmailLoginModal} onLogin={handleLogin} onSignup={openEmailSignupFromLogin} />}
{isEmailLoginModalOpen && <EmailLoginModal onClose={closeEmailLoginModal} onSignup={openEmailSignupFromLogin} />}
{isLoginConfirmationModalOpen && <LoginConfirmationModal onClose={handleLoginConfirmationClose} />}

{isEmailSignupModalOpen && <EmailSignupModal onClose={closeEmailSignupModal} onRequestVerification={openEmailVerificationModal} />}
Expand Down

0 comments on commit 7ca217e

Please sign in to comment.