Skip to content

Commit 1aee99d

Browse files
authored
Merge pull request #140 from pagers-org/carpe/improve-register-logic
feat(app): 회원 가입 완료시 JWT 토큰을 쿠키로 저장하고 인증이 필요한 요청에 Bearer 헤더를 설정하도록 합니다.
2 parents 57db0d6 + ddffb4b commit 1aee99d

9 files changed

+68
-10
lines changed

Diff for: .pnp.cjs

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.
11.5 KB
Binary file not shown.

Diff for: apps/react-world/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
"@tanstack/react-query-devtools": "^4.35.3",
1717
"@types/axios": "^0.14.0",
1818
"axios": "^1.5.0",
19+
"js-cookie": "^3.0.5",
1920
"react": "^18.2.0",
2021
"react-dom": "^18.2.0",
2122
"react-router-dom": "^6.15.0",
2223
"zustand": "^4.4.1"
2324
},
2425
"devDependencies": {
26+
"@types/js-cookie": "^3",
2527
"@types/react": "^18.2.15",
2628
"@types/react-dom": "^18.2.7",
2729
"@typescript-eslint/eslint-plugin": "^6.4.1",

Diff for: apps/react-world/src/apis/apiInstances.ts

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { AxiosRequestConfig } from 'axios';
22
import axios from 'axios';
3+
import Cookies from 'js-cookie';
34

45
// TODO: 향후 .env 파일로 분리
56
const BASE_URL = 'https://api.realworld.io/api';
@@ -12,14 +13,20 @@ const axiosApi = (url: string, options?: AxiosRequestConfig) => {
1213

1314
// POST, DELETE 등 요청 시 인증이 필요한 경우
1415
const axiosAuthApi = (url: string, options?: AxiosRequestConfig) => {
15-
const jwtToken = '토큰 값'; // TODO: 향후 개발
16-
const instance = axios.create({
17-
baseURL: url,
18-
headers: { Authorization: 'Bearer ' + jwtToken },
19-
...options,
20-
});
16+
const instance = axios.create({ baseURL: url, ...options });
2117
return instance;
2218
};
2319

2420
export const api = axiosApi(BASE_URL);
2521
export const authApi = axiosAuthApi(BASE_URL);
22+
23+
// 요청 전 JWT 쿠키 유무를 확인 후 Bearer 헤더 설정
24+
authApi.interceptors.request.use(config => {
25+
const jwtToken = Cookies.get('jwtToken');
26+
27+
if (jwtToken) {
28+
config.headers.Authorization = 'Bearer ' + jwtToken; // 토큰이 있을 때 헤더에 추가
29+
}
30+
31+
return config;
32+
});

Diff for: apps/react-world/src/apis/register/RegisterService.ts

+2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ class RegisterService {
1616
return response.data;
1717
} catch (error) {
1818
if (isAxiosError(error) && error.response) {
19+
console.error('Axios error occurred:', error.response.data);
1920
throw error.response.data;
2021
}
22+
console.error('An unexpected error occurred:', error);
2123
throw error;
2224
}
2325
}

Diff for: apps/react-world/src/hooks/useRegister.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
RegisterUserResponse,
66
} from '../apis/register/RegisterService.types';
77
import RegisterService from '../apis/register/RegisterService';
8+
import { saveTokenToCookie } from '@utils/jwtUtils';
89

910
const useRegister = () => {
1011
const [userData, setUserData] = useState<RegisterUserParams>({
@@ -31,14 +32,14 @@ const useRegister = () => {
3132
const response = await RegisterService.registerUser(userData);
3233
console.log('response: ' + JSON.stringify(response, null, 2));
3334

34-
// TODO: 임시로 로컬 스토리지에 토큰 저장
35-
localStorage.setItem('jwtToken', response.user.token);
35+
// JWT 토큰을 쿠키에 저장
36+
if (response && response.user && response.user.token) {
37+
saveTokenToCookie(response.user.token);
38+
}
3639

3740
setIsLoading(false);
3841
return response;
3942
} catch (error) {
40-
setIsLoading(false);
41-
4243
// TODO: 로그 제거
4344
console.log('error: ' + JSON.stringify(error, null, 2));
4445
if (error && typeof error === 'object' && 'errors' in error) {
@@ -47,6 +48,8 @@ const useRegister = () => {
4748
console.error('An unexpected error occurred:', error);
4849
}
4950
return null;
51+
} finally {
52+
setIsLoading(false);
5053
}
5154
};
5255

Diff for: apps/react-world/src/utils/jwtUtils.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Cookies from 'js-cookie';
2+
3+
export const saveTokenToCookie = (token: string) => {
4+
Cookies.set('jwtToken', token, {
5+
secure: true, // HTTPS에서만 쿠키 전송
6+
sameSite: 'lax', // CSRF 공격 방지를 위한 설정
7+
});
8+
};

Diff for: yarn.lock

+16
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,7 @@ __metadata:
817817
"@tanstack/react-query": ^4.35.3
818818
"@tanstack/react-query-devtools": ^4.35.3
819819
"@types/axios": ^0.14.0
820+
"@types/js-cookie": ^3
820821
"@types/react": ^18.2.15
821822
"@types/react-dom": ^18.2.7
822823
"@typescript-eslint/eslint-plugin": ^6.4.1
@@ -826,6 +827,7 @@ __metadata:
826827
eslint-plugin-prettier: ^5.0.0
827828
eslint-plugin-react: ^7.33.2
828829
eslint-plugin-react-hooks: ^4.6.0
830+
js-cookie: ^3.0.5
829831
react: ^18.2.0
830832
react-dom: ^18.2.0
831833
react-router-dom: ^6.15.0
@@ -916,6 +918,13 @@ __metadata:
916918
languageName: node
917919
linkType: hard
918920

921+
"@types/js-cookie@npm:^3":
922+
version: 3.0.4
923+
resolution: "@types/js-cookie@npm:3.0.4"
924+
checksum: 46ac93974776a256f3cedadf60b45ded4d905a5e69986882d8c17baa351cb2e81a691864a1f19c3ca90eaa2cb3eeb7cb5426416b487a7d54cf5ff278d39d7870
925+
languageName: node
926+
linkType: hard
927+
919928
"@types/json-schema@npm:^7.0.12":
920929
version: 7.0.12
921930
resolution: "@types/json-schema@npm:7.0.12"
@@ -3107,6 +3116,13 @@ __metadata:
31073116
languageName: node
31083117
linkType: hard
31093118

3119+
"js-cookie@npm:^3.0.5":
3120+
version: 3.0.5
3121+
resolution: "js-cookie@npm:3.0.5"
3122+
checksum: 2dbd2809c6180fbcf060c6957cb82dbb47edae0ead6bd71cbeedf448aa6b6923115003b995f7d3e3077bfe2cb76295ea6b584eb7196cca8ba0a09f389f64967a
3123+
languageName: node
3124+
linkType: hard
3125+
31103126
"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
31113127
version: 4.0.0
31123128
resolution: "js-tokens@npm:4.0.0"

0 commit comments

Comments
 (0)