-
Notifications
You must be signed in to change notification settings - Fork 2
feat: 로그인 기능구현 #52
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
feat: 로그인 기능구현 #52
Changes from all commits
b725a79
ca23169
30bc2f2
6da8353
b8f7c22
eb6cc62
ab4688e
38e5f01
1a5240f
f9004af
f789e93
7401575
57debf8
cb6b529
c8bba52
cce466e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| import client from './client'; | ||
|
|
||
| export const socialLogin = (loginType: LoginType) => { | ||
| window.location.href = `${import.meta.env.VITE_API_URL}/oauth2/authorization/${loginType}`; | ||
| }; | ||
|
|
||
| export const getUserToken = async (stateToken: string) => { | ||
| try { | ||
| const response = await client.get(`/api/auth/token?state=${stateToken}`); | ||
| if (!response) throw new Error('getUserToken: Error while fetching user token'); | ||
| const userInfo = response.data; | ||
| if (userInfo) { | ||
| return userInfo; | ||
| } | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| }; | ||
|
|
||
| export const postZipCode = async () => { | ||
| try { | ||
| const response = await client.post(`/api/members/zipCode`); | ||
| if (!response) throw new Error('fail to post ZipCode'); | ||
| return response; | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| }; | ||
|
|
||
| export const getNewToken = async () => { | ||
| try { | ||
| const response = await client.get('/api/reissue', { withCredentials: true }); | ||
| if (!response) throw new Error('getNewToken: no response data'); | ||
| return response; | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| }; | ||
|
|
||
| export const getMydata = async () => { | ||
| try { | ||
| const response = await client.get('/api/members/me'); | ||
| if (!response) throw new Error('getNewTOken: no response data'); | ||
| return response; | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| }; | ||
|
|
||
| export const deleteUserInfo = async () => { | ||
| try { | ||
| const response = await client.delete('/api/members/me', { | ||
| withCredentials: true, | ||
| }); | ||
| if (!response) throw new Error('deleteUserInfo: no response'); | ||
| return response; | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| }; | ||
|
|
||
| export const postLogout = async () => { | ||
| try { | ||
| const response = await client.post('/api/logout', { withCredentials: true }); | ||
| if (!response) throw new Error('postLogout: failed to logout'); | ||
| return response; | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| }; | ||
|
Collaborator
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를 여러개 호출 + 마침 토큰도 유효하지 않을 경우, 토큰 재발급 요청도 여러번 발생할 수 있을 것 같아요. 토큰 갱신이 한 번만 진행되도록 로직을 보완하면 어떨까요?! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,70 @@ | ||
| import axios from 'axios'; | ||
|
|
||
| import useAuthStore from '@/stores/authStore'; | ||
|
|
||
| import { getNewToken } from './auth'; | ||
|
|
||
| const client = axios.create({ | ||
| baseURL: import.meta.env.VITE_API_URL, | ||
| }); | ||
|
|
||
| // client.interceptors.request.use( | ||
| // (config) => { | ||
| // const token = localStorage.getItem('authToken'); | ||
| // if (token) { | ||
| // config.headers['Authorization'] = `Bearer ${token}`; | ||
| // } | ||
| // return config; | ||
| // }, | ||
| // (error) => { | ||
| // //TODO: 에러처리 | ||
| // return Promise.reject(error); | ||
| // }, | ||
| // ); | ||
| client.interceptors.request.use( | ||
| (config) => { | ||
| const accessToken = useAuthStore((state) => state.accessToken); | ||
| console.log(config.url); | ||
| console.log(accessToken); | ||
| if (config.url !== '/auth/reissue' && accessToken) { | ||
| config.headers.Authorization = `Bearer ${accessToken}`; | ||
| console.log('intercepter', config.headers); | ||
| } | ||
| return config; | ||
| }, | ||
| (error) => { | ||
| const logout = useAuthStore((state) => state.logout); | ||
| logout(); | ||
| window.location.replace('/login'); | ||
| return Promise.reject(error); | ||
|
Collaborator
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문의 요 코드는 콘솔창에 에러 출력하는 코드인가용? |
||
| }, | ||
| ); | ||
|
|
||
| client.interceptors.response.use( | ||
| (response) => response, | ||
| async (error) => { | ||
| const setAccessToken = useAuthStore((state) => state.setAccessToken); | ||
| const logout = useAuthStore((state) => state.logout); | ||
|
|
||
| const originalRequest = error.config; | ||
|
|
||
| if (!originalRequest) { | ||
| return Promise.reject(error); | ||
| } | ||
|
|
||
| if ( | ||
| (error.response.status === 401 || | ||
| error.response.status === 403 || | ||
| error.response.data.message === 'Unauthorized') && | ||
| !originalRequest._retry | ||
| ) { | ||
| originalRequest._retry = true; | ||
|
|
||
| try { | ||
| const response = await getNewToken(); | ||
| const newToken = response?.data.accessToken; | ||
|
|
||
| if (!newToken) throw new Error('Failed to Refresh Token'); | ||
|
|
||
| setAccessToken(newToken); | ||
| originalRequest.headers.Authorization = `Bearer ${newToken}`; | ||
|
|
||
| return client(originalRequest); | ||
| } catch (e) { | ||
| logout(); | ||
| window.location.replace('/login'); | ||
| return Promise.reject(e); | ||
| } | ||
| } | ||
| return Promise.reject(error); | ||
| }, | ||
| ); | ||
|
|
||
| export default client; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,11 +15,11 @@ queryClient.setDefaultOptions({ | |
| }); | ||
|
|
||
| createRoot(document.getElementById('root')!).render( | ||
| <StrictMode> | ||
| <QueryClientProvider client={queryClient}> | ||
| <BrowserRouter> | ||
| <App /> | ||
| </BrowserRouter> | ||
| </QueryClientProvider> | ||
| </StrictMode>, | ||
| // <StrictMode> | ||
| <QueryClientProvider client={queryClient}> | ||
| <BrowserRouter> | ||
| <App /> | ||
| </BrowserRouter> | ||
| </QueryClientProvider>, | ||
| // </StrictMode>, | ||
|
Comment on lines
+18
to
+24
Collaborator
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. 오잉 strictMode는 임시로 끄신건가용? |
||
| ); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| /* eslint-disable @typescript-eslint/no-unused-expressions */ | ||
| import { useEffect } from 'react'; | ||
| import { useNavigate } from 'react-router'; | ||
|
|
||
| import { getUserToken, getMydata, postZipCode } from '@/apis/auth'; | ||
| import useAuthStore from '@/stores/authStore'; | ||
|
|
||
| const AuthCallbackPage = () => { | ||
| const stateToken = new URLSearchParams(window.location.search).get('state'); | ||
| const redirectURL = new URLSearchParams(window.location.search).get('redirect'); | ||
|
Comment on lines
+9
to
+10
Collaborator
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. 소셜로그인 후 로그인 페이지 리다이렉트 될때 이 코드를 사용해서 토큰값을 저장하는걸까용?
Collaborator
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. 아닌가 유저 정보를 가져오는건가?!
Collaborator
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. redirectUrl은 로그인 이후에 온보딩으로 갈지 홈으로 갈지 정해주는 쿼리파라미터값 같은데 어느 페이지에서 넘어올때 이런 값들이 담겨져서 오는건가용??
Collaborator
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. 오호라 redirect까지 넘겨주시는걸로 백엔드 분과 얘기가 된 건가요?? (영섭님이었나) 저는 개인적으로 이 방식의 경우, 프론트 측에서 언제든지 path 변경을 할 수도 있고, 그런 상황에서는 백엔드 측에서도 같이 수정을 하는 번거로움이 있을 것 같다는 단점이 있다고 생각이 되어요. 그래서 새로운 유저인지 아닌지만 구분해서 넘겨주시면 저희가 홈으로 보낼지 온보딩으로 보낼지 로직을 처리하는 게 더 나을 것 같다는 의견이긴 합니다 |
||
|
|
||
| const login = useAuthStore((state) => state.login); | ||
| const setAccessToken = useAuthStore((state) => state.setAccessToken); | ||
| const setZipCode = useAuthStore((state) => state.setZipCode); | ||
|
|
||
| const navigate = useNavigate(); | ||
|
|
||
| const setUserInfo = async (stateToken: string) => { | ||
| try { | ||
| const response = await getUserToken(stateToken); | ||
| if (!response) throw new Error('Error Fetching userInfo'); | ||
|
|
||
| const userInfo = response.data; | ||
| if (userInfo) { | ||
| login(); | ||
| userInfo.accessToken && setAccessToken(userInfo.accessToken); | ||
|
|
||
| if (redirectURL == 'home') { | ||
|
Collaborator
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. 비교 연산자가 ===가 아닌 ==인 이유가 있을까용? |
||
| const zipCodeResponse = await getMydata(); | ||
| if (!zipCodeResponse) throw new Error('Error Fetching userInfo'); | ||
| const zipCode = zipCodeResponse.data.data.zipCode; | ||
| zipCode && setZipCode(zipCode); | ||
|
|
||
| console.log( | ||
| 'isLoggedIn', | ||
| useAuthStore.getState().isLoggedIn, | ||
| 'access', | ||
| useAuthStore.getState().accessToken, | ||
| 'zipCode', | ||
| useAuthStore.getState().zipCode, | ||
| ); | ||
| } else if (redirectURL === 'onboarding') { | ||
| const createZipCodeResponse = await postZipCode(); | ||
| if (!createZipCodeResponse) throw new Error('Error creating ZipCode'); | ||
| const zipCode = createZipCodeResponse.data.data.zipCode; | ||
| console.log(createZipCodeResponse); | ||
| const newAccessToken = createZipCodeResponse.headers['Authorization']; | ||
| setZipCode(zipCode); | ||
| setAccessToken(newAccessToken); | ||
| console.log( | ||
| 'isLoggedIn', | ||
| useAuthStore.getState().isLoggedIn, | ||
| 'access', | ||
| useAuthStore.getState().accessToken, | ||
| 'zipCode', | ||
| useAuthStore.getState().zipCode, | ||
| ); | ||
| } | ||
| } else { | ||
| navigate('/login'); | ||
| } | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| }; | ||
|
|
||
| const redirection = () => { | ||
| if (redirectURL === 'onboarding') navigate('/onboarding'); | ||
| else if (redirectURL === 'home') navigate('/'); | ||
| else navigate('/notFound'); | ||
|
Comment on lines
+68
to
+70
Collaborator
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. 혹시 이동된 페이지에서 뒤로가기 하면 여기로 다시 진입 가능한가욧?! |
||
| }; | ||
|
|
||
| useEffect(() => { | ||
| if (stateToken) { | ||
| setUserInfo(stateToken as string); | ||
| redirection(); | ||
| } else navigate('/notFound'); | ||
| }, []); | ||
| return <></>; | ||
| }; | ||
|
|
||
| export default AuthCallbackPage; | ||
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.
오잉 로그아웃 요청 함수가 2개 있네용?