React 서버 컴포넌트 보안 업데이트 권고

This commit is contained in:
2025-12-10 17:51:07 +09:00
parent d6f29f978d
commit cac963d2d7
5 changed files with 1319 additions and 506 deletions
+14 -3
View File
@@ -32,11 +32,22 @@ export class LoginApiService implements LoginService {
});
const data = await response.json();
console.log('data ', data)
const accessToken = data[ACCESS_TOKEN];
const tokenId = data[AUTH_USER_ID];
if (!accessToken || !tokenId) {
throw new Error("Missing required authentication tokens");
if (data.message == 'Invalid Credentials' ) {
throw new Error('아이디와 비밀번호가 일치하지 않습니다.');
} else if (data.message == 'User not found') {
throw new Error('존재하지 않는 아이디입니다.');
} else if (data.message == 'User is not active') {
throw new Error('활성화되지 않은 계정입니다.');
} else if (data.message == 'User is not verified') {
throw new Error('이메일 인증이 필요합니다.');
} else {
throw new Error(data.message);
}
}
tokenManager.setToken(CLAIM_NAME, accessToken);
@@ -47,9 +58,9 @@ export class LoginApiService implements LoginService {
);
} catch (error) {
if (error instanceof AxiosError) {
throw new Error(`Login failed: ${error.response?.data?.message}`);
throw new Error(`Login 실패 ${error.response?.data?.message}`);
}
throw new Error(`Login failed: ${error}`);
throw new Error(`Login 실패 ${error}`);
}
}
+17 -2
View File
@@ -1,20 +1,30 @@
"use client";
import { useState } from "react";
import Image from "next/image";
import { images } from "@common/assets";
import { LoginApi } from "@/entities/auth";
import "./login.css";
function LoginPage() {
const [errorMessage, setErrorMessage] = useState<string>("");
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setErrorMessage(""); // 에러 메시지 초기화
const formData = new FormData(e.target as HTMLFormElement);
const userId = formData.get("id") as string;
const password = formData.get("password") as string;
await LoginApi.login({ userId, password });
window.location.href = "/dashboard";
try {
await LoginApi.login({ userId, password });
window.location.href = "/dashboard";
} catch (error) {
const message =
error instanceof Error ? error.message : "로그인에 실패했습니다.";
setErrorMessage(message);
}
};
return (
@@ -81,6 +91,11 @@ function LoginPage() {
</div>
{/* <a href="javascript:fnUserSearch();" className=" pw_message fx"><i className="xi-external-link"></i>비밀번호 또는 아이디를 잃어버리셨나요?</a> */}
</div>
{errorMessage && (
<div className="error_message">
<span>{errorMessage}</span>
</div>
)}
<button type="submit" className="login_btn fx">
<span>LOGIN</span>
</button>
+14
View File
@@ -118,6 +118,20 @@ body {
color: #327af5;
font-size: 20px;
}
.login .login_box .error_message {
margin: 20px 0;
padding: 12px 20px;
background: #fee;
border: 1px solid #fcc;
border-radius: 5px;
color: #c33;
font-size: 14px;
text-align: center;
}
.login .login_box .error_message span {
display: block;
font-weight: 500;
}
.login .login_box .login_btn {
position: relative;
border-radius: 5px;
+6 -6
View File
@@ -25,16 +25,16 @@
"preinstall": "npx only-allow pnpm"
},
"dependencies": {
"chart.js": "^4.4.8",
"chart.js": "^4.5.1",
"react": "^18.3.1",
"react-chartjs-2": "^5.3.0",
"react-chartjs-2": "^5.3.1",
"react-dom": "^18.3.1",
"zustand": "^5.0.3"
"zustand": "^5.0.9"
},
"devDependencies": {
"@types/node": "^22.13.9",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@types/node": "^22.19.2",
"@types/react": "^18.3.27",
"@types/react-dom": "^18.3.7",
"turbo": "2.4.2"
},
"pnpm": {
+1268 -495
View File
File diff suppressed because it is too large Load Diff