From e94f195783257b1faa0a076116acaa010b5ebf6d Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Sat, 24 Feb 2024 19:13:32 +0900 Subject: [PATCH 01/13] =?UTF-8?q?feat:=20refresh=20token=20method=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/configs/axios.ts | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/configs/axios.ts b/src/configs/axios.ts index fff78587..e788eccd 100644 --- a/src/configs/axios.ts +++ b/src/configs/axios.ts @@ -9,25 +9,39 @@ export const API = axios.create({ : import.meta.env.VITE_DEV_SERVER_URL, }); +//Auth export const setAuth = (token: string): unknown => (API.defaults.headers['Authorization'] = token); export const resetAuth = (): unknown => delete API.defaults.headers['Authorization']; -const storageKey = 'CAUCSE_JWT'; +const storageAuthKey = 'CAUCSE_JWT_AUTH'; export const storeAuth = (isStored: boolean, token: string): void => { - if (isStored) localStorage.setItem(storageKey, token); - else sessionStorage.setItem(storageKey, token); + if (isStored) localStorage.setItem(storageAuthKey, token); + else sessionStorage.setItem(storageAuthKey, token); }; export const restoreAuth = (): boolean => { - const token = localStorage.getItem(storageKey) ?? sessionStorage.getItem(storageKey); + const token = localStorage.getItem(storageAuthKey) ?? sessionStorage.getItem(storageAuthKey); if (token) setAuth(token); return !!token; }; export const removeAuth = (): void => { - localStorage.removeItem(storageKey); - sessionStorage.removeItem(storageKey); + localStorage.removeItem(storageAuthKey); + sessionStorage.removeItem(storageAuthKey); +}; + +//Refresh +const storageRefreshKey = 'CAUCSE_JWT_REFRESH'; + +export const storeRefresh = (token: string): void => { + localStorage.setItem(storageRefreshKey, token); +}; +export const removeRefresh = (): void => { + localStorage.removeItem(storageRefreshKey); +}; +export const getRefresh = (): string | null => { + return localStorage.getItem(storageRefreshKey); }; API.interceptors.response.use( From 4d6c426f935426717021d0a902f57e6ba35e6b8d Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Sat, 24 Feb 2024 19:38:45 +0900 Subject: [PATCH 02/13] =?UTF-8?q?refactor:=20signin=20system=20refrash=20t?= =?UTF-8?q?oken=20=EC=B6=94=EA=B0=80=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/repositories/AuthRepo.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/stores/repositories/AuthRepo.ts b/src/stores/repositories/AuthRepo.ts index 7c319544..01356402 100644 --- a/src/stores/repositories/AuthRepo.ts +++ b/src/stores/repositories/AuthRepo.ts @@ -2,16 +2,20 @@ import { AxiosResponse } from 'axios'; import { UserModel } from '../models/UserModel'; -import { API, setAuth, storeAuth } from '@/configs/axios'; +import { API, setAuth, storeAuth, storeRefresh } from '@/configs/axios'; class AuthRepo { URI = '/api/v1/users'; signIn = async (body: User.SignInRequestDto) => { - const { data: token } = (await API.post(`${this.URI}/sign-in`, body)) as AxiosResponse; - - storeAuth(true, token); - setAuth(token); + const { data } = (await API.post(`${this.URI}/sign-in`, body)) as AxiosResponse<{ + accessToken: string; + refreshToken: string; + }>; + + storeAuth(true, data.accessToken); + setAuth(data.accessToken); + storeRefresh(data.refreshToken); }; isDuplicatedEmail = async (email: string): Promise => { From 41720529e77295fd4722cbcba35144c2b117f0a8 Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Sat, 24 Feb 2024 20:25:26 +0900 Subject: [PATCH 03/13] =?UTF-8?q?feat:=20updateAccessToken=20method=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20API.interceptors.response.use=20=ED=99=9C?= =?UTF-8?q?=EC=9A=A9=20=EC=9E=AC=EB=B0=9C=EA=B8=89=20=EC=8B=9C=EC=8A=A4?= =?UTF-8?q?=ED=85=9C=20=EC=B6=94=EA=B0=80=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/@types/user.d.ts | 5 +++++ src/configs/axios.ts | 26 +++++++++++++++++++++++--- src/stores/repositories/AuthRepo.ts | 28 +++++++++++++++++++++++----- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/@types/user.d.ts b/src/@types/user.d.ts index a620269e..c5499055 100644 --- a/src/@types/user.d.ts +++ b/src/@types/user.d.ts @@ -181,6 +181,11 @@ declare namespace User { updatedPassword: string; } + export interface UpdateAccessTokenRequestDto { + accessToken: string | null; + refreshToken: string; + } + // == export interface FindPostsResponse { diff --git a/src/configs/axios.ts b/src/configs/axios.ts index e788eccd..a9d58b02 100644 --- a/src/configs/axios.ts +++ b/src/configs/axios.ts @@ -2,6 +2,8 @@ import axios from 'axios'; import { PAGE_URL } from './path'; +import { AuthRepoImpl as Repo } from '@/stores/repositories/AuthRepo'; + export const API = axios.create({ baseURL: process.env.NODE_ENV === 'production' @@ -48,9 +50,8 @@ API.interceptors.response.use( response => response, error => { if (error.response) { - const { - response: { data }, - } = error; + const { response, configs } = error; + let data = response.data; // 4012: 접근 권한이 없습니다. 다시 로그인 해주세요. 문제 반복시 관리자에게 문의해주세요. // 4103: 비활성화된 사용자 입니다. @@ -61,6 +62,25 @@ API.interceptors.response.use( if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; } + // 4019?? : UnAuthorizedException , 만료된 access 토큰입니다. + if (data.errorCode === 4019) { + if (localStorage.getItem(storageRefreshKey)) { + Repo.updateAccessToken({ + accessToken: localStorage.getItem(storageAuthKey), + refreshToken: localStorage.getItem(storageRefreshKey)!, + }) + .then(() => { + return API.request(configs); + }) + .catch(error => { + data = error.response.data; + if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; + }); + } + + if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; + } + return Promise.reject({ success: false, ...data, diff --git a/src/stores/repositories/AuthRepo.ts b/src/stores/repositories/AuthRepo.ts index 01356402..5c6b8e8c 100644 --- a/src/stores/repositories/AuthRepo.ts +++ b/src/stores/repositories/AuthRepo.ts @@ -2,20 +2,22 @@ import { AxiosResponse } from 'axios'; import { UserModel } from '../models/UserModel'; -import { API, setAuth, storeAuth, storeRefresh } from '@/configs/axios'; +import { API, setAuth, storeAuth, storeRefresh, removeAuth, removeRefresh } from '@/configs/axios'; class AuthRepo { URI = '/api/v1/users'; signIn = async (body: User.SignInRequestDto) => { - const { data } = (await API.post(`${this.URI}/sign-in`, body)) as AxiosResponse<{ + const { + data: { accessToken, refreshToken }, + } = (await API.post(`${this.URI}/sign-in`, body)) as AxiosResponse<{ accessToken: string; refreshToken: string; }>; - storeAuth(true, data.accessToken); - setAuth(data.accessToken); - storeRefresh(data.refreshToken); + storeAuth(true, accessToken); + setAuth(accessToken); + storeRefresh(refreshToken); }; isDuplicatedEmail = async (email: string): Promise => { @@ -44,6 +46,22 @@ class AuthRepo { updatePassword = async (body: User.PasswordUpdateRequestDto) => { return API.put(`${this.URI}/password`, body); }; + + updateAccessToken = async (body: User.UpdateAccessTokenRequestDto) => { + const { + data: { accessToken, refreshToken }, + } = (await API.post(`${this.URI}/token/updatePutmapping`, body)) as AxiosResponse<{ + accessToken: string; + refreshToken: string; + }>; + + removeAuth(); + removeRefresh(); + + storeAuth(true, accessToken); + setAuth(accessToken); + storeRefresh(refreshToken); + }; } export const AuthRepoImpl = new AuthRepo(); From 0718dbea0c0cef1b6f2d5a5056ab2f4ed2b6bbc0 Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Mon, 26 Feb 2024 00:20:48 +0900 Subject: [PATCH 04/13] =?UTF-8?q?feat:=20API=20=EC=88=98=EC=A0=95=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/@types/user.d.ts | 1 - src/configs/axios.ts | 1 - src/mocks/handlers/authHandler.ts | 15 +++++++++++++++ src/stores/repositories/AuthRepo.ts | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 src/mocks/handlers/authHandler.ts diff --git a/src/@types/user.d.ts b/src/@types/user.d.ts index c5499055..49a706a5 100644 --- a/src/@types/user.d.ts +++ b/src/@types/user.d.ts @@ -182,7 +182,6 @@ declare namespace User { } export interface UpdateAccessTokenRequestDto { - accessToken: string | null; refreshToken: string; } diff --git a/src/configs/axios.ts b/src/configs/axios.ts index a9d58b02..1fad4106 100644 --- a/src/configs/axios.ts +++ b/src/configs/axios.ts @@ -66,7 +66,6 @@ API.interceptors.response.use( if (data.errorCode === 4019) { if (localStorage.getItem(storageRefreshKey)) { Repo.updateAccessToken({ - accessToken: localStorage.getItem(storageAuthKey), refreshToken: localStorage.getItem(storageRefreshKey)!, }) .then(() => { diff --git a/src/mocks/handlers/authHandler.ts b/src/mocks/handlers/authHandler.ts new file mode 100644 index 00000000..b3c81aa8 --- /dev/null +++ b/src/mocks/handlers/authHandler.ts @@ -0,0 +1,15 @@ +import { http, ResponseResolver, HttpResponse } from 'msw'; + +const getAccessTokenHandler: ResponseResolver = () => { + return HttpResponse.json({ + accessToken: 'string', + refreshToken: 'string', + }); +}; + +export const AusthHandler = [ + http.get('/api/v1/users/token/updatePutmapping', getAccessTokenHandler), + http.get('/api/v1/users/me', (req, res, context) => + res(context.status(200), context.json({ data: 'some-random-fake-data' })), + ), +]; diff --git a/src/stores/repositories/AuthRepo.ts b/src/stores/repositories/AuthRepo.ts index 5c6b8e8c..a676b67c 100644 --- a/src/stores/repositories/AuthRepo.ts +++ b/src/stores/repositories/AuthRepo.ts @@ -50,7 +50,7 @@ class AuthRepo { updateAccessToken = async (body: User.UpdateAccessTokenRequestDto) => { const { data: { accessToken, refreshToken }, - } = (await API.post(`${this.URI}/token/updatePutmapping`, body)) as AxiosResponse<{ + } = (await API.put(`${this.URI}/token/update`, body)) as AxiosResponse<{ accessToken: string; refreshToken: string; }>; From 11309eecb35b1159b5b6cdf5940b86485eca4dc2 Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Mon, 26 Feb 2024 01:42:55 +0900 Subject: [PATCH 05/13] =?UTF-8?q?fix:=20axios=20token.=20=EC=9E=AC?= =?UTF-8?q?=EB=B0=9C=EA=B8=89=20=EA=B3=BC=EC=A0=95=20=EC=88=98=EC=A0=95,?= =?UTF-8?q?=20mocking=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/configs/axios.ts | 6 ++--- src/mocks/handlers/authHandler.ts | 37 ++++++++++++++++++++++++------- src/mocks/handlers/index.ts | 2 ++ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/configs/axios.ts b/src/configs/axios.ts index 1fad4106..8a995561 100644 --- a/src/configs/axios.ts +++ b/src/configs/axios.ts @@ -62,7 +62,7 @@ API.interceptors.response.use( if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; } - // 4019?? : UnAuthorizedException , 만료된 access 토큰입니다. + // 4019로 가정 : UnAuthorizedException , 만료된 access 토큰입니다. if (data.errorCode === 4019) { if (localStorage.getItem(storageRefreshKey)) { Repo.updateAccessToken({ @@ -75,9 +75,7 @@ API.interceptors.response.use( data = error.response.data; if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; }); - } - - if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; + } else if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; } return Promise.reject({ diff --git a/src/mocks/handlers/authHandler.ts b/src/mocks/handlers/authHandler.ts index b3c81aa8..8b4ae831 100644 --- a/src/mocks/handlers/authHandler.ts +++ b/src/mocks/handlers/authHandler.ts @@ -1,15 +1,36 @@ import { http, ResponseResolver, HttpResponse } from 'msw'; -const getAccessTokenHandler: ResponseResolver = () => { - return HttpResponse.json({ - accessToken: 'string', - refreshToken: 'string', +const postSignInHandler: ResponseResolver = () => { + return HttpResponse.json<{ + accessToken: string; + refreshToken: string; + }>({ + accessToken: 'accessToken', + refreshToken: 'refreshToken', }); }; -export const AusthHandler = [ - http.get('/api/v1/users/token/updatePutmapping', getAccessTokenHandler), - http.get('/api/v1/users/me', (req, res, context) => - res(context.status(200), context.json({ data: 'some-random-fake-data' })), +const putAccessTokenHandler: ResponseResolver = () => { + return HttpResponse.json<{ + accessToken: string; + refreshToken: string; + }>({ + accessToken: 'accessToken2', + refreshToken: 'refreshToken2', + }); +}; + +const accessTokenErrorHandler: ResponseResolver = () => { + return new HttpResponse(null, { + status: 401, + }); +}; + +export const authHandler = [ + http.post(import.meta.env.VITE_DEV_SERVER_URL + '/api/v1/users/sign-in', postSignInHandler), + http.put( + import.meta.env.VITE_DEV_SERVER_URL + '/api/v1/users/token/update', + putAccessTokenHandler, ), + http.get(import.meta.env.VITE_DEV_SERVER_URL + '/api/v1/users/me', accessTokenErrorHandler), ]; diff --git a/src/mocks/handlers/index.ts b/src/mocks/handlers/index.ts index 70585f7c..3f6306ba 100644 --- a/src/mocks/handlers/index.ts +++ b/src/mocks/handlers/index.ts @@ -1,3 +1,4 @@ +import { authHandler } from './authHandler'; import { boardHandler } from './boardHandler'; import { circleHandler } from './circleHandler'; import { commentHandler } from './commentHandler'; @@ -16,6 +17,7 @@ const handlers = [ ...lockerHandler, ...historyHandler, ...settingHandler, + ...authHandler, ]; export default handlers; From af3cf9f4f21853d7e953c686336f743ab497e6c5 Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Mon, 26 Feb 2024 02:21:02 +0900 Subject: [PATCH 06/13] =?UTF-8?q?fix:=20axios=20token=20=EC=9E=AC=EB=B0=9C?= =?UTF-8?q?=EA=B8=89=20=EA=B3=BC=EC=A0=95=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EB=B6=80=EB=B6=84=20=EC=88=98=EC=A0=95=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/configs/axios.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/configs/axios.ts b/src/configs/axios.ts index 8a995561..64defdb2 100644 --- a/src/configs/axios.ts +++ b/src/configs/axios.ts @@ -59,6 +59,7 @@ API.interceptors.response.use( if (data.errorCode === 4012 || data.errorCode === 4103 || data.errorCode === 4105) { removeAuth(); + removeRefresh(); if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; } @@ -72,10 +73,16 @@ API.interceptors.response.use( return API.request(configs); }) .catch(error => { + removeAuth(); + removeRefresh(); data = error.response.data; if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; }); - } else if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; + } else if (location.pathname !== PAGE_URL.SignIn) { + removeAuth(); + removeRefresh(); + location.href = PAGE_URL.SignIn; + } } return Promise.reject({ From d023864cdcaf31ff92528e5ce6d833dc60055d5f Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Tue, 27 Feb 2024 16:43:21 +0900 Subject: [PATCH 07/13] =?UTF-8?q?fix:=20axios=20token=20=EC=9E=AC=EB=B0=9C?= =?UTF-8?q?=EA=B8=89=20error=20code=20=EB=B3=80=EA=B2=BD=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/configs/axios.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/configs/axios.ts b/src/configs/axios.ts index 64defdb2..91b7ca60 100644 --- a/src/configs/axios.ts +++ b/src/configs/axios.ts @@ -53,18 +53,8 @@ API.interceptors.response.use( const { response, configs } = error; let data = response.data; - // 4012: 접근 권한이 없습니다. 다시 로그인 해주세요. 문제 반복시 관리자에게 문의해주세요. - // 4103: 비활성화된 사용자 입니다. - // 4015: 다시 로그인 해주세요. - - if (data.errorCode === 4012 || data.errorCode === 4103 || data.errorCode === 4105) { - removeAuth(); - removeRefresh(); - if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; - } - - // 4019로 가정 : UnAuthorizedException , 만료된 access 토큰입니다. - if (data.errorCode === 4019) { + // 4105로 가정 + if (data.errorCode === '4105') { if (localStorage.getItem(storageRefreshKey)) { Repo.updateAccessToken({ refreshToken: localStorage.getItem(storageRefreshKey)!, From e080a640f4d7cef8a9376c18df2d695c74f5bc4e Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Tue, 27 Feb 2024 17:01:55 +0900 Subject: [PATCH 08/13] =?UTF-8?q?fix:=20configs=20->=20config=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/configs/axios.ts | 4 ++-- src/index.tsx | 6 ++---- src/mocks/handlers/authHandler.ts | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/configs/axios.ts b/src/configs/axios.ts index 91b7ca60..ddf07b26 100644 --- a/src/configs/axios.ts +++ b/src/configs/axios.ts @@ -50,7 +50,7 @@ API.interceptors.response.use( response => response, error => { if (error.response) { - const { response, configs } = error; + const { response, config } = error; let data = response.data; // 4105로 가정 @@ -60,7 +60,7 @@ API.interceptors.response.use( refreshToken: localStorage.getItem(storageRefreshKey)!, }) .then(() => { - return API.request(configs); + return API.request(config); }) .catch(error => { removeAuth(); diff --git a/src/index.tsx b/src/index.tsx index 8b653212..58174274 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -18,8 +18,7 @@ render( document.getElementById('root'), ); -/* mocking -async function enableMocking() { +/* async function enableMocking() { if (process.env.NODE_ENV !== 'development') { return; } @@ -39,5 +38,4 @@ enableMocking().then(() => { , document.getElementById('root'), ); -}); -*/ +}); */ diff --git a/src/mocks/handlers/authHandler.ts b/src/mocks/handlers/authHandler.ts index 8b4ae831..6a33a6d7 100644 --- a/src/mocks/handlers/authHandler.ts +++ b/src/mocks/handlers/authHandler.ts @@ -27,10 +27,10 @@ const accessTokenErrorHandler: ResponseResolver = () => { }; export const authHandler = [ - http.post(import.meta.env.VITE_DEV_SERVER_URL + '/api/v1/users/sign-in', postSignInHandler), + // http.post(import.meta.env.VITE_DEV_SERVER_URL + '/api/v1/users/sign-in', postSignInHandler), http.put( import.meta.env.VITE_DEV_SERVER_URL + '/api/v1/users/token/update', putAccessTokenHandler, ), - http.get(import.meta.env.VITE_DEV_SERVER_URL + '/api/v1/users/me', accessTokenErrorHandler), + // http.get(import.meta.env.VITE_DEV_SERVER_URL + '/api/v1/users/me', accessTokenErrorHandler), ]; From d2229674dcb4808383cf7b161cc522dd2aaf04b7 Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Tue, 27 Feb 2024 18:52:44 +0900 Subject: [PATCH 09/13] =?UTF-8?q?refacror:=20=EB=B3=B4=EC=95=88=20?= =?UTF-8?q?=EC=83=81=20access=20token=20=EB=B3=80=EC=88=98=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/configs/axios.ts | 25 +++---------------------- src/stores/AuthStore.tsx | 10 +++------- src/stores/repositories/AuthRepo.ts | 9 +++------ 3 files changed, 9 insertions(+), 35 deletions(-) diff --git a/src/configs/axios.ts b/src/configs/axios.ts index ddf07b26..6b098e35 100644 --- a/src/configs/axios.ts +++ b/src/configs/axios.ts @@ -12,26 +12,9 @@ export const API = axios.create({ }); //Auth -export const setAuth = (token: string): unknown => (API.defaults.headers['Authorization'] = token); -export const resetAuth = (): unknown => delete API.defaults.headers['Authorization']; - -const storageAuthKey = 'CAUCSE_JWT_AUTH'; - -export const storeAuth = (isStored: boolean, token: string): void => { - if (isStored) localStorage.setItem(storageAuthKey, token); - else sessionStorage.setItem(storageAuthKey, token); -}; -export const restoreAuth = (): boolean => { - const token = localStorage.getItem(storageAuthKey) ?? sessionStorage.getItem(storageAuthKey); - - if (token) setAuth(token); - - return !!token; -}; -export const removeAuth = (): void => { - localStorage.removeItem(storageAuthKey); - sessionStorage.removeItem(storageAuthKey); -}; +export const setAccess = (token: string): unknown => + (API.defaults.headers['Authorization'] = token); +export const resetAccess = (): unknown => delete API.defaults.headers['Authorization']; //Refresh const storageRefreshKey = 'CAUCSE_JWT_REFRESH'; @@ -63,13 +46,11 @@ API.interceptors.response.use( return API.request(config); }) .catch(error => { - removeAuth(); removeRefresh(); data = error.response.data; if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; }); } else if (location.pathname !== PAGE_URL.SignIn) { - removeAuth(); removeRefresh(); location.href = PAGE_URL.SignIn; } diff --git a/src/stores/AuthStore.tsx b/src/stores/AuthStore.tsx index 290f1f80..857336f3 100644 --- a/src/stores/AuthStore.tsx +++ b/src/stores/AuthStore.tsx @@ -2,7 +2,7 @@ import { makeAutoObservable } from 'mobx'; import { AuthRepoImpl as Repo } from './repositories/AuthRepo'; -import { removeAuth, restoreAuth } from '@/configs/axios'; +import { getRefresh, removeRefresh } from '@/configs/axios'; export class AuthStore { rootStore: Store.Root; @@ -26,23 +26,19 @@ export class AuthStore { } *checkToken(): Generator { - //Token 존재 확인 - if (!restoreAuth()) return { success: false }; - //Token 유효성 확인 try { this.me = (yield Repo.findCurrentUser()) as Model.User; return { success: true }; } catch (err) { - removeAuth(); return err; } } signOut(): void { - removeAuth(); + removeRefresh(); } get isSignIn(): boolean { - return restoreAuth(); + return getRefresh() ? true : false; } } diff --git a/src/stores/repositories/AuthRepo.ts b/src/stores/repositories/AuthRepo.ts index a676b67c..a59562e0 100644 --- a/src/stores/repositories/AuthRepo.ts +++ b/src/stores/repositories/AuthRepo.ts @@ -2,7 +2,7 @@ import { AxiosResponse } from 'axios'; import { UserModel } from '../models/UserModel'; -import { API, setAuth, storeAuth, storeRefresh, removeAuth, removeRefresh } from '@/configs/axios'; +import { API, setAccess, storeRefresh, removeAuth, removeRefresh } from '@/configs/axios'; class AuthRepo { URI = '/api/v1/users'; @@ -15,8 +15,7 @@ class AuthRepo { refreshToken: string; }>; - storeAuth(true, accessToken); - setAuth(accessToken); + setAccess(accessToken); storeRefresh(refreshToken); }; @@ -55,11 +54,9 @@ class AuthRepo { refreshToken: string; }>; - removeAuth(); removeRefresh(); - storeAuth(true, accessToken); - setAuth(accessToken); + setAccess(accessToken); storeRefresh(refreshToken); }; } From 4b06d6dceef5e3b9f75ee06702b150eaa677ddfc Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Tue, 27 Feb 2024 19:28:21 +0900 Subject: [PATCH 10/13] =?UTF-8?q?fix:=20findAllLocation=20api=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20(#81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/@types/locker.d.ts | 4 ++-- src/mocks/data/locker.ts | 4 ++-- .../list/components/LockerListCard/LockerListCard.tsx | 4 ++-- .../locations/components/LocationGrid/LocationCell.tsx | 8 +++++++- src/stores/models/LockerModel.ts | 4 ++-- src/stores/repositories/LockerRepo.ts | 10 +++++----- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/@types/locker.d.ts b/src/@types/locker.d.ts index 26c4e64b..09f29d70 100644 --- a/src/@types/locker.d.ts +++ b/src/@types/locker.d.ts @@ -2,14 +2,14 @@ declare namespace Locker { export interface Dto { id: string; name: string; - description: string; + //description: string; enableLockerCount: number; totalLockerCount: number; } export interface LocationDto { id: string; lockerNumber: number; - lockerLocationName: string; + //lockerLocationName: string; updatedAt: string; expireAt: string; isActive: boolean; diff --git a/src/mocks/data/locker.ts b/src/mocks/data/locker.ts index 81466d9b..9af6b39f 100644 --- a/src/mocks/data/locker.ts +++ b/src/mocks/data/locker.ts @@ -4,7 +4,7 @@ export const lockerAllLocationsList: Locker.FindAllLocationResponseDto = { { id: '3', name: 'locker_location', - description: 'description', + //description: 'description', enableLockerCount: 0, totalLockerCount: 0, }, @@ -16,7 +16,7 @@ export const lockerAllLocationsList: Locker.FindAllLocationResponseDto = { isMine: true, lockerNumber: 1, updatedAt: '2024-01-22T09:50:43.175Z', - lockerLocationName: 'lockerLocationName', //problem: Swagger API에 없음 + //lockerLocationName: 'lockerLocationName', //problem: Swagger API에 없음 }, }; diff --git a/src/pages/locker/list/components/LockerListCard/LockerListCard.tsx b/src/pages/locker/list/components/LockerListCard/LockerListCard.tsx index 6aba2a3c..c41c1f18 100644 --- a/src/pages/locker/list/components/LockerListCard/LockerListCard.tsx +++ b/src/pages/locker/list/components/LockerListCard/LockerListCard.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from 'react'; import { Bar, Card, Desc, Name, Status } from './styled'; export const LockerListCard: React.FC<{ model: Model.Locker }> = ({ - model: { to, name, description, enableLockerCount, totalLockerCount }, + model: { to, name, enableLockerCount, totalLockerCount }, }) => { const [progress, setProgress] = useState(0); @@ -14,7 +14,7 @@ export const LockerListCard: React.FC<{ model: Model.Locker }> = ({ return ( {name} - {description} + {/* {description} */} 잔여 {enableLockerCount} / 전체 {totalLockerCount} diff --git a/src/pages/locker/locations/components/LocationGrid/LocationCell.tsx b/src/pages/locker/locations/components/LocationGrid/LocationCell.tsx index 60cb5032..fd937370 100644 --- a/src/pages/locker/locations/components/LocationGrid/LocationCell.tsx +++ b/src/pages/locker/locations/components/LocationGrid/LocationCell.tsx @@ -13,7 +13,13 @@ export const LocationCell: React.FC<{ model: Model.LockerLocation }> = observer( const isSelected = computed(() => store.target?.id === model.id).get(); return ( - + {lockerNumber} ); diff --git a/src/stores/models/LockerModel.ts b/src/stores/models/LockerModel.ts index 6de49e5e..8d6e48e6 100644 --- a/src/stores/models/LockerModel.ts +++ b/src/stores/models/LockerModel.ts @@ -5,14 +5,14 @@ import { PAGE_URL } from '@/configs/path'; export class LockerModel implements Locker.Dto { id: string; name: string; - description: string; + //description: string; enableLockerCount: number; totalLockerCount: number; constructor(props: Locker.Dto) { this.id = props.id; this.name = props.name; - this.description = props.description; + //this.description = props.description; this.enableLockerCount = props.enableLockerCount; this.totalLockerCount = props.totalLockerCount; } diff --git a/src/stores/repositories/LockerRepo.ts b/src/stores/repositories/LockerRepo.ts index 68cc5347..c553d76e 100644 --- a/src/stores/repositories/LockerRepo.ts +++ b/src/stores/repositories/LockerRepo.ts @@ -72,21 +72,21 @@ class LockerDummyRepo { new LockerModel({ id: '1', name: '3층 사물함', - description: '208관 3층 312호 앞', + //description: '208관 3층 312호 앞', enableLockerCount: 80, totalLockerCount: 100, }), new LockerModel({ id: '2', name: '4층 사물함', - description: '208관 4층 407호 앞', + //description: '208관 4층 407호 앞', enableLockerCount: 160, totalLockerCount: 160, }), new LockerModel({ id: '3', name: '5층 사물함', - description: '208관 5층 515호 앞', + //description: '208관 5층 515호 앞', enableLockerCount: 80, totalLockerCount: 160, }), @@ -101,7 +101,7 @@ class LockerDummyRepo { new LockerLocationModel({ id: 'test', lockerNumber: 0, - lockerLocationName: '0번', + //lockerLocationName: '0번', updatedAt: '', expireAt: '', isActive: true, @@ -115,7 +115,7 @@ class LockerDummyRepo { new LockerLocationModel({ id: `test-${index + 1}`, lockerNumber: index + 1, - lockerLocationName: `${index + 1}번`, + //lockerLocationName: `${index + 1}번`, updatedAt: '', expireAt: '', isActive: Math.random() > 0.5, From 7e59e5b36471286915be72c4191477584563b6ac Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Tue, 27 Feb 2024 19:49:47 +0900 Subject: [PATCH 11/13] fix: register, return, extend, findAllLocation (#81) --- src/@types/locker.d.ts | 11 ++++++----- .../list/components/LockerPosition/LockerPosition.tsx | 3 +-- src/stores/models/LockerLocationModel.ts | 4 ++-- src/stores/repositories/LockerRepo.ts | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/@types/locker.d.ts b/src/@types/locker.d.ts index 09f29d70..788305e0 100644 --- a/src/@types/locker.d.ts +++ b/src/@types/locker.d.ts @@ -29,15 +29,16 @@ declare namespace Locker { export interface FindByLocationResponseDto { locationName: string; lockerList: LockerLocationDto[]; - /* - LockerLocationDto may be: id: string; + } + + interface LockerLocationDto { + id: string; lockerNumber: number; - lockerLocationName: string; + //lockerLocationName: string; updatedAt: string; expireAt: string; isActive: boolean; - isMine: boolean; - */ + isMine: boolean; } export interface FindByLocationResponse { diff --git a/src/pages/locker/list/components/LockerPosition/LockerPosition.tsx b/src/pages/locker/list/components/LockerPosition/LockerPosition.tsx index b4149439..1b38ea79 100644 --- a/src/pages/locker/list/components/LockerPosition/LockerPosition.tsx +++ b/src/pages/locker/list/components/LockerPosition/LockerPosition.tsx @@ -6,9 +6,8 @@ export const LockerPosition: React.FC<{ model?: Model.LockerLocation }> = observ model ? ( 보유중인 사물함 - {model.lockerLocationName} {model.lockerNumber}번

+ {model.lockerNumber} 번

마감기한 : {model.expireAt}
) : null, - ); diff --git a/src/stores/models/LockerLocationModel.ts b/src/stores/models/LockerLocationModel.ts index 9a977b84..609d7808 100644 --- a/src/stores/models/LockerLocationModel.ts +++ b/src/stores/models/LockerLocationModel.ts @@ -3,7 +3,7 @@ import { action, makeObservable, observable } from 'mobx'; export class LockerLocationModel implements Locker.LocationDto { id: string; lockerNumber: number; - lockerLocationName: string; + //lockerLocationName: string; updatedAt: string; expireAt: string; isActive: boolean; @@ -12,7 +12,7 @@ export class LockerLocationModel implements Locker.LocationDto { constructor(props: Locker.LocationDto) { this.id = props.id; this.lockerNumber = props.lockerNumber; - this.lockerLocationName = props.lockerLocationName; + //this.lockerLocationName = props.lockerLocationName; this.updatedAt = props.updatedAt; this.expireAt = props.expireAt; this.isActive = props.isActive; diff --git a/src/stores/repositories/LockerRepo.ts b/src/stores/repositories/LockerRepo.ts index c553d76e..c3cae018 100644 --- a/src/stores/repositories/LockerRepo.ts +++ b/src/stores/repositories/LockerRepo.ts @@ -44,21 +44,21 @@ class LockerRepo { }; register = async (lockerId: string): Promise => { - return await API.put(`${this.URI}/${lockerId}`, { action: 'register' }); + return await API.put(`${this.URI}/${lockerId}`, { action: 'register', message: '' }); //mocking //return axios.put(`${this.URI}/${lockerId}`, { action: 'register' }); }; return = async (lockerId: string): Promise => { - return await API.put(`${this.URI}/${lockerId}`, { action: 'return' }); + return await API.put(`${this.URI}/${lockerId}`, { action: 'return', message: '' }); //mocking //return axios.put(`${this.URI}/${lockerId}`, { action: 'return' }); }; extend = async (lockerId: string): Promise => { - return await API.put(`${this.URI}/${lockerId}`, { action: 'extend' }); + return await API.put(`${this.URI}/${lockerId}`, { action: 'extend', message: '' }); //mocking //return axios.put(`${this.URI}/${lockerId}`, { action: 'extend' }); From 61eba8f94ed2d75cbbfd91c0812dcc4790c03ce0 Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Thu, 29 Feb 2024 14:49:31 +0900 Subject: [PATCH 12/13] =?UTF-8?q?fix:=20config=20error=20=EB=B0=8F=20error?= =?UTF-8?q?=20=EB=AC=B4=ED=95=9C=20=EB=B0=98=EB=B3=B5=20=ED=95=B4=EA=B2=B0?= =?UTF-8?q?=20(#81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/configs/axios.ts | 49 +++++++++++++++-------------- src/stores/repositories/AuthRepo.ts | 16 +--------- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/configs/axios.ts b/src/configs/axios.ts index 6b098e35..edb63864 100644 --- a/src/configs/axios.ts +++ b/src/configs/axios.ts @@ -1,9 +1,7 @@ -import axios from 'axios'; +import axios, { AxiosResponse } from 'axios'; import { PAGE_URL } from './path'; -import { AuthRepoImpl as Repo } from '@/stores/repositories/AuthRepo'; - export const API = axios.create({ baseURL: process.env.NODE_ENV === 'production' @@ -31,29 +29,32 @@ export const getRefresh = (): string | null => { API.interceptors.response.use( response => response, - error => { + async error => { if (error.response) { - const { response, config } = error; - let data = response.data; + const { + response: { data }, + config, + } = error; + + if (!localStorage.getItem(storageRefreshKey) || config.url === '/api/v1/users/token/update') { + removeRefresh(); + if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; + } else if (data.errorCode === '4105') { + const { + data: { accessToken, refreshToken }, + } = (await API.put(`/api/v1/users/token/update`, { + refreshToken: getRefresh(), + })) as AxiosResponse<{ + accessToken: string; + refreshToken: string; + }>; + + setAccess(accessToken); + removeRefresh(); + storeRefresh(refreshToken); - // 4105로 가정 - if (data.errorCode === '4105') { - if (localStorage.getItem(storageRefreshKey)) { - Repo.updateAccessToken({ - refreshToken: localStorage.getItem(storageRefreshKey)!, - }) - .then(() => { - return API.request(config); - }) - .catch(error => { - removeRefresh(); - data = error.response.data; - if (location.pathname !== PAGE_URL.SignIn) location.href = PAGE_URL.SignIn; - }); - } else if (location.pathname !== PAGE_URL.SignIn) { - removeRefresh(); - location.href = PAGE_URL.SignIn; - } + config.headers['Authorization'] = accessToken; + return API.request(config); } return Promise.reject({ diff --git a/src/stores/repositories/AuthRepo.ts b/src/stores/repositories/AuthRepo.ts index a59562e0..0017e164 100644 --- a/src/stores/repositories/AuthRepo.ts +++ b/src/stores/repositories/AuthRepo.ts @@ -2,7 +2,7 @@ import { AxiosResponse } from 'axios'; import { UserModel } from '../models/UserModel'; -import { API, setAccess, storeRefresh, removeAuth, removeRefresh } from '@/configs/axios'; +import { API, setAccess, storeRefresh, removeRefresh } from '@/configs/axios'; class AuthRepo { URI = '/api/v1/users'; @@ -45,20 +45,6 @@ class AuthRepo { updatePassword = async (body: User.PasswordUpdateRequestDto) => { return API.put(`${this.URI}/password`, body); }; - - updateAccessToken = async (body: User.UpdateAccessTokenRequestDto) => { - const { - data: { accessToken, refreshToken }, - } = (await API.put(`${this.URI}/token/update`, body)) as AxiosResponse<{ - accessToken: string; - refreshToken: string; - }>; - - removeRefresh(); - - setAccess(accessToken); - storeRefresh(refreshToken); - }; } export const AuthRepoImpl = new AuthRepo(); From 2200ef4dce4e29c820c2c5e14470d83f405e2473 Mon Sep 17 00:00:00 2001 From: selfishAltruism Date: Thu, 29 Feb 2024 20:06:24 +0900 Subject: [PATCH 13/13] =?UTF-8?q?refactor:=20AuthRouter.ts=20auth=20check?= =?UTF-8?q?=20=EA=B3=BC=EC=A0=95=20=EC=A0=9C=EA=B1=B0=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AuthRouter.tsx | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/AuthRouter.tsx b/src/AuthRouter.tsx index fdee451a..f4b92559 100644 --- a/src/AuthRouter.tsx +++ b/src/AuthRouter.tsx @@ -1,33 +1,10 @@ import { observer } from 'mobx-react-lite'; -import { useEffect } from 'react'; -import { useHistory, useLocation, Route, Redirect } from 'react-router-dom'; - -import { PAGE_URL } from '@/configs/path'; -import { useRootStore } from '@/stores/RootStore'; +import { Route } from 'react-router-dom'; type Props = { children?: React.ReactNode; }; export const AuthRouter: React.FC = observer(({ children, ...rest }) => { - const { - auth: { checkToken }, - } = useRootStore(); - const history = useHistory(); - const location = useLocation(); - - const isTokenAvailable = async () => { - const { success } = (await checkToken()) as unknown as StoreAPI; - if (!success) - history.push({ - pathname: PAGE_URL.SignIn, - state: { from: location }, - }); - }; - - useEffect(() => { - isTokenAvailable(); - }, []); - return children} />; });