Skip to content

Commit

Permalink
fix: refreshToken 사용하도록 수정
Browse files Browse the repository at this point in the history
  • Loading branch information
ptyoiy committed May 12, 2024
1 parent e2b1d80 commit f43145a
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 34 deletions.
14 changes: 11 additions & 3 deletions src/api/axios/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ export function login(id: number, kakao_accessToken: string) {

export const kakaoLogout = async (client: QueryClient, navigate: NavigateFunction) => {
console.log('logout called');
return axios.post('/logout').then(() => {
return axios.post('/logout', {
refreshToken: localStorage.getItem('refreshToken')
}).then(() => {
localStorage.removeItem('info');
localStorage.removeItem('accessToken');
localStorage.removeItem('refreshToken');
client.removeQueries({ queryKey: ['login'] });
client.removeQueries({ queryKey: ['userInfo'] });
Expand All @@ -37,4 +38,11 @@ export const kakaoLogout = async (client: QueryClient, navigate: NavigateFunctio
export const getUserInfo = async (id: number) => {
console.log('get UserInfo called');
return axios.get(`/users/info/${id}`).then(res => res.data);
}
}

export const getAccessToken = async (refreshToken: string) => {
console.log('get accessToken called');
return axios.post(`/getToken`, {
refreshToken
}).then(res => res.data);
}
38 changes: 33 additions & 5 deletions src/api/query/user.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { login } from "../axios";
import { getUserInfo, loginResponse } from "../axios/user";
import { AxiosError } from "axios";
import { useContext, useEffect } from "react";
import { LocalStorage } from "../../context";
import { IUser, User } from "../../context/user.d";
import { login } from "../axios";
import { getAccessToken, getUserInfo } from "../axios/user";

export const loginQuery = (id: number, kakao_accessToken: string) => {
const info = useQuery({
Expand All @@ -15,8 +18,9 @@ export const loginQuery = (id: number, kakao_accessToken: string) => {
};

export const getUserInfoQuery = () => {
const client = useQueryClient();
const loginData = client.getQueryData<IUser>(['login']);
const queryClient = useQueryClient();
const { dispatch } = useContext(LocalStorage);
const loginData = queryClient.getQueryData<IUser>(['login']);
const userInfo = useQuery({
queryKey: ['userInfo'],
queryFn: () => getUserInfo(loginData.id),
Expand All @@ -25,7 +29,31 @@ export const getUserInfoQuery = () => {
select(data) {
const { alarm, bookmark, eventLike, noticeLike, noticeRead } = data;
return new User(loginData, alarm, bookmark, noticeRead, noticeLike, eventLike);
}
},
retry(failureCount, error: AxiosError) {
// 401 == accessToken 문제(쿠키에 없거나 만료, 유효하지 않음)
// 403 == refreshToken 문제(access와 동일)
// 기본값 3회 시도 후 종료
return error.response.status != 401;
},
})
const { isError } = userInfo;
useEffect(() => {
const fetchNewAccessToken = async () => {
try {
const refreshToken = localStorage.getItem('refreshToken');
await getAccessToken(refreshToken);
// 쿠키에 저장된 새로운 AccessToken으로 이전에 실패한 쿼리 다시 실행
await queryClient.invalidateQueries({ queryKey: ['userInfo'] });
} catch (error) {
// RefreshToken이 만료된 경우 context정보 삭제
dispatch({ payload: 'reset' });
}
};

if (isError) {
fetchNewAccessToken();
}
}, [isError])
return userInfo;
}
10 changes: 4 additions & 6 deletions src/components/Login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,24 @@ import { LocalStorage } from "../../context";

export const Login = memo(() => {
const navigate = useNavigate();
const {initData, dispatch} = useContext(LocalStorage);
const { initData, dispatch } = useContext(LocalStorage);

const [{ id, access_token }, setLoginData] = useState({ id: undefined, access_token: undefined });
const { data } = loginQuery(id, access_token);

const onSuccess: Props['onSuccess'] = async ({ response, profile }) => {
console.log('kakao login success', { response, profile });
const { id } = profile;
const { access_token, refresh_token } = response;
const { access_token } = response;
setLoginData({ id, access_token });
}

useEffect(() => {
console.log({data})
if (data?.user) {
dispatch({
payload: 'setLoginInfo',
data: {
info: data.user,
accessToken: data.accessToken,
refreshToken: data.refreshToken
}
})
Expand All @@ -36,9 +34,9 @@ export const Login = memo(() => {
useEffect(() => {
if (data?.create || (initData.info && !initData.major)) {
navigate('/setmajor', { replace: true });
}
}
if (initData.info && initData.major) {
navigate('/my', {replace: true});
navigate('/my', { replace: true });
}
}, [initData.info])

Expand Down
25 changes: 14 additions & 11 deletions src/context/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ import { IUser } from "./user";
export const LocalStorage = createContext<{ initData: State, dispatch: Dispatch<Action> }>(null);
const info = localStorage.getItem('info');
const major = localStorage.getItem('major');
const accessToken = localStorage.getItem('accessToken');
const refreshToken = localStorage.getItem('refreshToken');

export const LocalStorageProvider = ({ children }) => {
const [initData, dispatch] = useReducer(reducer, {
info: info ? JSON.parse(info) : undefined,
major,
accessToken,
refreshToken
});
const queryClient = useQueryClient();
Expand All @@ -28,7 +26,7 @@ export const LocalStorageProvider = ({ children }) => {
}
}, [initData.major])

console.log({ initData, info, accessToken })
console.log({ initData })
return (
<LocalStorage.Provider value={{ initData, dispatch }}>
{children}
Expand All @@ -39,38 +37,43 @@ export const LocalStorageProvider = ({ children }) => {
function reducer(state: State, { payload, data }: Action) {
switch (payload) {
case 'setLoginInfo': {
const { accessToken, refreshToken, info } = data;
const { refreshToken, info } = data;
localStorage.setItem('info', JSON.stringify(info));
localStorage.setItem('major', info.major);
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('refreshToken', refreshToken);
return { major: info.major, info, accessToken, refreshToken };
return { major: info.major, info, refreshToken };
}
case 'setMajor': {
localStorage.setItem('major', data);
return { ...state, major: data }
}
case 'reset': {
localStorage.removeItem('info');
localStorage.removeItem('refreshToken');
localStorage.removeItem('major'); // TODO: login 모달 완성시 제거
return { info: undefined, refreshToken: undefined, major }
}
}
}

interface SetLoginInfoAction {
payload: 'setLoginInfo';
data: {
info: IUser
accessToken: string
refreshToken: string
}
}

interface SetMajorAction {
payload: 'setMajor';
data: string;
}

interface ResetAction {
payload: 'reset';
data?: undefined;
}
type State = {
info: SetLoginInfoAction['data']['info']
major: SetMajorAction['data'],
accessToken: SetLoginInfoAction['data']['accessToken'],
refreshToken: SetLoginInfoAction['data']['refreshToken']
}
type Action = SetLoginInfoAction | SetMajorAction;
type Action = SetLoginInfoAction | SetMajorAction | ResetAction;
17 changes: 8 additions & 9 deletions src/pages/SignupPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Button, Select } from "@mui/material";
import { Login } from "../../components/Login";
import { useNavigate } from "react-router-dom";
import { Button } from "@mui/material";
import { useContext, useState } from "react";
import { useNavigate } from "react-router-dom";
import ChatGray from "../../assets/Img/ChatGray.png";
import VisLogoSrc from "../../assets/Img/VislabLogo.png";
import CseyLogoSrc from "../../assets/Img/splashLogo.png";
import { Login } from "../../components/Login";
import { LocalStorage } from "../../context";
import * as s from "./styles";
import CseyLogoSrc from "../../assets/Img/splashLogo.png"
import VisLogoSrc from "../../assets/Img/VislabLogo.png"
import ChatYellow from "../../assets/Img/ChatYellow.png"
import ChatGray from "../../assets/Img/ChatGray.png"

export const Signup = () => {
const [showLogin, setShowLogin] = useState(false);
Expand All @@ -18,8 +17,8 @@ export const Signup = () => {
return (
<s.Container>
<s.CseyLogo src={CseyLogoSrc} onAnimationEnd={handleAnimationEnd} />
{/* <Login></Login> */}
<s.Member src={ChatYellow} show={showLogin} onClick={() => navigate('/setmajor')} />
<Login></Login>
{/* <s.Member src={ChatYellow} show={showLogin} onClick={() => navigate('/setmajor')} /> */}
<s.NonMember src={ChatGray} show={showLogin} onClick={() => navigate('/setmajor')} />
<s.VisLogo src={VisLogoSrc} />
</s.Container>
Expand Down

0 comments on commit f43145a

Please sign in to comment.