-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
페이지 기능: 로그인 이후 토큰 인증에 따라 로그인 만료, 로그인 연장 처리 #182
Changes from all commits
0345769
a44cb1c
64ae761
c30b2b2
489aeae
05dec8e
fe575c1
8f45e5b
c96dbd1
98851c5
4e0101e
b7a5ad4
6bf2343
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import useRefreshToken from '@remote/queries/auth/useRefreshToken'; | ||
|
||
const JWT_EXPIRY_TIME = 14 * 60 * 1000; | ||
|
||
function useIntervalRefreshToken() { | ||
const { mutate: refresh } = useRefreshToken(); | ||
let refreshTokenInterval: NodeJS.Timeout; | ||
|
||
const startRefreshTokenInterval = () => { | ||
refreshTokenInterval = setInterval(() => { | ||
refresh(); | ||
}, JWT_EXPIRY_TIME); | ||
}; | ||
|
||
const refreshTokenClear = () => { | ||
clearInterval(refreshTokenInterval); | ||
}; | ||
|
||
return { startRefreshTokenInterval, refreshTokenClear }; | ||
} | ||
|
||
export default useIntervalRefreshToken; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { useCookies } from 'react-cookie'; | ||
|
||
import { useQueryClient } from '@tanstack/react-query'; | ||
import { useRouter } from 'next/navigation'; | ||
|
||
import { useAppDispatch } from '@stores/hooks'; | ||
import { clearUserId } from '@stores/slices/userSlice'; | ||
|
||
function useLoggedOut() { | ||
const router = useRouter(); | ||
const dispatch = useAppDispatch(); | ||
const query = useQueryClient(); | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
const [cookies, removeCookie] = useCookies(['token']); | ||
|
||
const logout = (redirectPath = '/') => { | ||
dispatch(clearUserId()); | ||
removeCookie('token', { path: '/' }); | ||
query.clear(); | ||
router.push(redirectPath); | ||
}; | ||
|
||
return logout; | ||
} | ||
|
||
export default useLoggedOut; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* ----- 로그인 MOCK DATA ----- */ | ||
export const MOCK_LOGIN_DATA = { | ||
status: 200, | ||
code: 'BMC002', | ||
message: '로그인 성공', | ||
value: { | ||
memberNo: 7251, | ||
id: 'stest0123', | ||
email: '[email protected]', | ||
password: null, | ||
gender: 'woman', | ||
age: '30', | ||
createdAt: '2024-02-19', | ||
createdBy: 'admin', | ||
modifiedAt: '2024-02-19', | ||
modifiedBy: 'admin', | ||
jwtToken: 'test-abcdefg1234--abc', | ||
}, | ||
}; | ||
|
||
/* ----- 토큰 MOCK DATA ----- */ | ||
export const MOCK_TOKEN_DATA = { | ||
status: 202, | ||
code: 'success', | ||
message: '토큰 인증 성공', | ||
value: { | ||
jwtToken: 'success-test-abcdefg1234--abc', | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* eslint-disable react-hooks/exhaustive-deps */ | ||
/* eslint-disable react/jsx-no-useless-fragment */ | ||
/* eslint-disable no-console */ | ||
|
||
'use client'; | ||
|
||
import { useEffect } from 'react'; | ||
|
||
import useIntervalRefreshToken from '@hooks/useIntervalRefreshToken'; | ||
import { useAppSelector } from '@stores/hooks'; | ||
|
||
function RefreshTokenProvider({ children }: { children: React.ReactNode }) { | ||
const { startRefreshTokenInterval, refreshTokenClear } = useIntervalRefreshToken(); | ||
const userId = useAppSelector((state) => { return state.user.id; }); | ||
|
||
useEffect(() => { | ||
if (userId !== null) { | ||
startRefreshTokenInterval(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 기존에 가지고 있던 토큰을 이용해서 새로운 토큰을 발급 받을 예정이신거죠? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵 지용님이랑 얘기해봤는데 헤더 Authentication에 담아 보내주면 body에 새로운 토큰을 넣어서 보내주신다고 하십니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아하 알겠습니다! |
||
console.log('RefreshTokenProvider mounted'); | ||
} | ||
|
||
// cleanup 함수를 이용하여 컴포넌트가 unmount 될 때 clearInterval 호출 | ||
return () => { | ||
refreshTokenClear(); | ||
console.log('RefreshTokenProvider unmounted'); | ||
}; | ||
}, [userId]); | ||
|
||
return <>{children}</>; | ||
} | ||
|
||
export default RefreshTokenProvider; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import { | ||
ChangePassword, | ||
FindId, FindPassword, ISignIn, ISignUp, UserInfoType, | ||
FindId, FindPassword, RefreshTokenType, ISignIn, ISignUp, UserInfoType, | ||
} from '../../types/auth'; | ||
import { ICommon } from '../../types/common'; | ||
import { postRequest, putRequest } from '../requests.api'; | ||
|
@@ -25,6 +25,12 @@ export const login = async ({ | |
return response; | ||
}; | ||
|
||
export const refreshToken = async () => { | ||
const response = await postRequest<RefreshTokenType, null>('/auth/validToken'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 api는 지용님이 만들어주실 예정인가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아마 그러실 것 같아요. 개발 예정이라고 하셨습니다! |
||
|
||
return response; | ||
}; | ||
|
||
export const findId = async ({ | ||
email, | ||
}: FindId) => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* eslint-disable no-console */ | ||
import { useCookies } from 'react-cookie'; | ||
|
||
import { useMutation } from '@tanstack/react-query'; | ||
|
||
import useLoggedOut from '@hooks/useLoggedOut'; | ||
import { refreshToken } from '@remote/api/requests/auth/auth.post.api'; | ||
import { RefreshTokenType } from '@remote/api/types/auth'; | ||
|
||
function useRefreshToken() { | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
const [cookies, setCookie, removeCookie] = useCookies(['token']); | ||
const handleLogout = useLoggedOut(); | ||
|
||
const onSuccess = (data: RefreshTokenType) => { | ||
const { jwtToken } = data.value; | ||
const cookieOptions = { path: '/', maxAge: 60 * 15 }; | ||
|
||
setCookie('token', jwtToken, cookieOptions); | ||
}; | ||
|
||
const onError = () => { | ||
handleLogout('/login'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 다시 로그인 해주세요 표시를 토스트로 보여줘도 될 것 같네요 |
||
}; | ||
|
||
return useMutation({ | ||
mutationFn: refreshToken, | ||
onSuccess, | ||
onError, | ||
}); | ||
} | ||
|
||
export default useRefreshToken; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거 두개로 나누지 않고 조건문으로 분기 처리할 수 있지 않나요?