JWT(JSON Web Token)는 웹 애플리케이션에서 사용자 인증 및 권한 관리를 구현하는 데 널리 사용됩니다. 역할 기반 접근 제어(RBAC)를 통해 사용자의 권한을 관리하고, 보안을 강화할 수 있습니다. 이번 포스팅에서는 JWT를 사용하여 사용자 권한과 역할을 관리하는 방법을 Node.js 환경에서 구현하는 과정을 설명하겠습니다.
1. 역할 기반 접근 제어
- RBAC(Role-Based Access Control)
- 사용자의 역할에 따라 시스템 자원에 대한 접근 권한을 제어하는 방법
- 각 사용자는 특정 역할(role)을 할당받으며, 각 역할은 시스템에서 수행할 수 있는 작업(permissions)을 정의하고, 이를 통해 사용자별로 세분화된 권한을 설정하고 보안을 강화.
- 예시 역할: 사용자(User), 관리자(Admin), 슈퍼 관리자(SuperAdmin)
- 권한 예시: 읽기(Read), 쓰기(Write), 삭제(Delete)
2. Node.js에서 JWT 설정 및 구현
[프로젝트 초기화 및 JWT 라이브러리 설치]
- express: 서버를 구현하기 위한 웹 프레임워크
- jsonwebtoken: JWT를 생성하고 검증하기 위한 라이브러리
- bcryptjs: 비밀번호를 안전하게 해싱하고 검증하기 위한 라이브러리
mkdir jwt-auth-example
cd jwt-auth-example
npm init -y
npm install express jsonwebtoken bcryptjs
[기본 Express 서버 설정]
- /register: 사용자가 회원가입을 하며, 비밀번호는 해싱되어 저장
- /login: 사용자가 로그인하면, 사용자의 역할과 함께 JWT가 발급
// server.js
import express from 'express';
import jwt from 'jsonwebtoken';
import bcrypt from 'bcryptjs';
const app = express();
const SECRET_KEY = 'your_secret_key';
app.use(express.json());
let users = [];
// 회원가입 엔드포인트
app.post('/register', async (req, res) => {
const { username, password, role } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
users.push({ username, password: hashedPassword, role });
res.status(201).json({ message: 'User registered successfully' });
});
// 로그인 엔드포인트
app.post('/login', async (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username);
if (!user) return res.status(404).json({ message: 'User not found' });
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(403).json({ message: 'Invalid credentials' });
const token = jwt.sign({ username: user.username, role: user.role }, SECRET_KEY, { expiresIn: '1h' });
res.json({ token });
});
// 서버 시작
app.listen(3000, () => {
console.log('Server running on <http://localhost:3000>');
});
3. 사용자 권한 및 역할 할당하기
JWT 페이로드에는 사용자의 역할을 포함할 수 있어, 사용자가 시스템에서 어떤 권한을 갖고 있는지 관리 가능.
회원가입 시 사용자가 역할(role)을 선택할 수 있게 하고, 로그인 시 역할 정보를 포함한 JWT를 생성
- 사용자 역할: User, Admin
- JWT 페이로드: { "username": "john_doe", "role": "Admin" }
// 페이로드에 역할 포함
const token = jwt.sign(
{ username: user.username, role: user.role },
SECRET_KEY,
{ expiresIn: '1h' }
);
4. JWT를 활용한 역할 기반 접근 제어
[미들웨어로 권한 검사 구현]
JWT를 활용해 사용자의 역할을 확인하고, 특정 API 엔드포인트에 대한 접근을 제어 가능.
// 권한 확인 미들웨어
const authorize = (roles) => {
return (req, res, next) => {
const token = req.headers['authorization'];
if (!token) return res.status(401).json({ message: 'Access token required' });
try {
const decoded = jwt.verify(token.split(' ')[1], SECRET_KEY);
if (!roles.includes(decoded.role)) {
return res.status(403).json({ message: 'Forbidden: You do not have the right permissions' });
}
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({ message: 'Invalid token' });
}
};
};
[관리자 전용 API 엔드포인트]
Admin 역할을 가진 사용자만 /admin 경로에 접근할 수 있도록 설정
authorize 미들웨어는 JWT를 검사하고, 사용자 역할이 Admin이 아니면 접근 차단
// 관리자 전용 엔드포인트
app.get('/admin', authorize(['Admin']), (req, res) => {
res.json({ message: 'Welcome Admin!' });
});
5. 보안 강화: JWT 만료 및 갱신 처리
[JWT 만료 설정]
JWT는 만료 시간이 설정된 유효한 토큰이어야 하므로, 보안을 강화하기 위해 만료 시간(expiresIn)을 설정
const token = jwt.sign({ username: user.username, role: user.role }, SECRET_KEY, { expiresIn: '1h' });
[토큰 갱신 처리]
토큰이 만료되기 전에 새로운 토큰을 발급해주는 방식으로 보안 강화 가능.
"Refresh Token"을 사용하여 유효한 토큰을 재발급받는 엔드포인트를 구현 필요
// 기존 토큰이 만료되었을 때 새로운 토큰을 발급
app.post('/refresh-token', (req, res) => {
const token = req.headers['authorization'];
if (!token) return res.status(401).json({ message: 'Access token required' });
try {
const decoded = jwt.verify(token.split(' ')[1], SECRET_KEY, { ignoreExpiration: true });
const newToken = jwt.sign({ username: decoded.username, role: decoded.role }, SECRET_KEY, { expiresIn: '1h' });
res.json({ token: newToken });
} catch (error) {
return res.status(401).json({ message: 'Invalid token' });
}
});
이번 포스팅에서는 Node.js 환경에서 JWT를 활용한 사용자 권한 관리 및 역할 기반 접근 제어를 구현하는 방법을 살펴보았습니다. JWT를 사용하면 사용자 권한을 보다 안전하고 효율적으로 관리할 수 있으며, 역할 기반 접근 제어를 통해 시스템의 보안을 강화할 수 있습니다.
'개발정리 (nodeJS)' 카테고리의 다른 글
[nodeJS] Node.js에서 GraphQL 서브스크립션 구현하기 (3) | 2024.09.23 |
---|---|
[nodeJS] Node.js로 GraphQL API 구현하기 (2) | 2024.09.18 |
[nodeJS] Node.js와 Elasticsearch를 사용한 검색 기능 구현하기 (0) | 2024.09.13 |
[nodeJS] Node.js로 PDF 생성 및 처리하기 (1) | 2024.09.09 |
[nodeJS] Node.js에서 시계열 데이터베이스 적용하기 (0) | 2024.09.03 |