Node.js와 ReactJS로 완성하는 JWT 인증 시스템: 백엔드와 프론트엔드 구현
2024-10-29 00:07:24webdevjavascriptnodetypescript
Node.js와 ReactJS로 JWT 기반 인증 구현하기
JWT(JSON Web Token)는 API를 안전하게 보호하기 위해 널리 사용되는 인증 방법이며, 특히 HTTP 헤더를 통해 인증 데이터를 전달하는 데 유용합니다. Node.js 백엔드와 ReactJS 프론트엔드에서 JWT를 사용해 인증 시스템을 구축하는 방법을 단계별로 알아보겠습니다.
Node.js를 사용한 백엔드 설정
백엔드에서는 Express와 TypeScript를 활용해 JWT를 생성하고 검증하는 기능을 구성합니다.
프로젝트 설정 및 환경 구성
먼저, Node.js 프로젝트를 설정하고 필요한 패키지를 설치합니다.
npm init -y
npm install express jsonwebtoken bcryptjs dotenv
npm install -D typescript @types/node @types/express @types/jsonwebtoken @types/bcryptjs ts-node
타입스크립트 설정을 위한 tsconfig.json 파일을 생성합니다.
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
서버 기본 구조 구성
기본적인 서버와 라우트를 설정합니다.
server.ts
import express, { Application } from 'express';
import dotenv from 'dotenv';
import authRoutes from './routes/authRoutes';
dotenv.config();
const app: Application = express();
app.use(express.json());
app.use('/api/auth', authRoutes);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Servidor rodando na porta ${PORT}`));
authRoutes.ts
로그인 요청을 처리하고, 사용자 인증 후 JWT를 반환합니다.
import express, { Request, Response } from 'express';
import jwt from 'jsonwebtoken';
import bcrypt from 'bcryptjs';
const router = express.Router();
// 간단한 사용자 데이터 시뮬레이션
const users = [{ username: 'usuario', password: 'senha123' }];
router.post('/login', async (req: Request, res: Response) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username);
if (!user || !(await bcrypt.compare(password, user.password))) {
return res.status(401).json({ message: 'Credenciais inválidas' });
}
const token = jwt.sign({ username }, process.env.JWT_SECRET as string, { expiresIn: '1h' });
res.json({ token });
});
export default router;
인증이 필요한 경로 보호하기
인증 미들웨어를 추가해서 보호해야 할 경로에 대한 접근을 제어합니다.
authMiddleware.ts
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
interface JwtPayload {
username: string;
}
export const authMiddleware = (req: Request, res: Response, next: NextFunction): void => {
const token = req.headers['authorization'];
if (!token) {
res.status(403).json({ message: 'Token não fornecido' });
return;
}
jwt.verify(token, process.env.JWT_SECRET as string, (err, decoded) => {
if (err) {
res.status(401).json({ message: 'Token inválido' });
return;
}
req.user = decoded as JwtPayload;
next();
});
};
ReactJS를 활용한 프론트엔드 설정
프론트엔드에서는 사용자가 입력한 로그인 정보를 처리하고, 발급받은 JWT를 사용해 보호된 리소스에 접근합니다.
로그인 UI 및 인증 요청 처리
Login 컴포넌트에서 사용자의 입력을 받아 로그인 프로세스를 처리합니다.
Login.tsx
import React, { useState } from 'react';
import axios from 'axios';
const Login: React.FC = () => {
const [username, setUsername] = useState<string>('');
const [password, setPassword] = useState<string>('');
const [error, setError] = useState<string>('');
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
try {
const response = await axios.post('/api/auth/login', { username, password });
localStorage.setItem('token', response.data.token);
window.location.href = '/dashboard';
} catch (err) {
setError('Credenciais inválidas');
}
};
return (
<form onSubmit={handleLogin}>
<input
type="text"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Login</button>
{error && <p>{error}</p>}
</form>
);
};
export default Login;
보호된 라우트 구성
JWT가 있어야 접근할 수 있는 보호된 라우트를 구성합니다.
PrivateRoute.tsx
import React from 'react';
import { Route, Redirect, RouteProps } from 'react-router-dom';
interface PrivateRouteProps extends RouteProps {
component: React.ComponentType<any>;
}
const PrivateRoute: React.FC<PrivateRouteProps> = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={(props) =>
localStorage.getItem('token') ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
export default PrivateRoute;
JWT를 포함한 요청 처리
axios를 사용하여 보호된 요청에 JWT를 자동으로 포함시킵니다.
axiosConfig.ts
import axios from 'axios';
const token = localStorage.getItem('token');
if (token) {
axios.defaults.headers.common['Authorization'] = token;
}
export default axios;
예시로 보호된 대시보드 페이지 만들기
JWT가 필요한 예시 페이지를 만들어 봅시다.
Dashboard.tsx
import React, { useEffect, useState } from 'react';
import axios from './axiosConfig';
const Dashboard: React.FC = () => {
const [data, setData] = useState<string>('');
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get('/api/protected');
setData(response.data.message);
} catch (error) {
console.error(error);
}
};
fetchData();
}, []);
return <h1>{data || 'Carregando...'}</h1>;
};
export default Dashboard;
결론
이 포스트에서는 Node.js와 ReactJS를 사용한 JWT 인증 시스템을 구축하는 과정을 살펴보았습니다. 효율적인 웹 애플리케이션 개발에 JWT를 활용하는 것은 사용자 데이터 보호와 세션 관리를 간편하게 하여 전반적인 보안성을 향상시킵니다.