Node.js의 Express 웹 애플리케이션 프레임워크를 사용하면 RESTful API, 웹사이트, 단순한 웹 서버를 빠르게 구축할 수 있습니다.
카카오 REST API를 사용하여 카카오 API를 활용하는 웹 서버를 빠르게 구축하기 위해 Node 서버를 선택하였습니다.
JWT 토큰은 API와 Node.js 서버 간의 인증 및 권한 부여 과정에서 중요한 역할을 하며, 사용자 정보를 안전하게 전달하고 서버의 부하를 줄이는 데 기여합니다.
JWT (JSON Web Token) 의 역할은 무엇인가요?
- 헤더는 토큰의 유형과 서명 알고리즘 정보를 포함합니다.
- 페이로드는 사용자 정보 및 기타 클레임을 포함합니다.
- 헤더와 페이로드를 조합한 후, 비밀 키를 사용하여 서명을 생성합니다. 이 서명은 JWT의 무결성을 검증하는 데 사용됩니다. 비밀 키는 토큰에 포함되지 않으며, 서버 측에서만 유지됩니다.
서버는 생성한 JWT 토큰을 클라이언트에게 응답으로 보냅니다. 클라이언트는 이 토큰을 로컬 스토리지나 쿠키에 저장하여 이후 요청 시 서버에 포함시켜 사용합니다.
JWT 토큰 안에는 유효기간(exp)을 설정할 수 있습니다. 만약 엑세스 토큰이 만료되면, 클라이언트는 사용자에게 다시 로그인하도록 요청하거나 리프레시 토큰을 통해 새로운 액세스 토큰을 발급받을 수 있습니다.
MongoDB를 사용한 이유?
- 카카오 로그인 API를 통해 사용자 정보를 수집하게 되면, MongoDB의 BSON 형식을 이용하여 유연하게 사용자 데이터를 저장할 수 있습니다. 사용자 정보는 JSON과 유사한 형태로 저장되므로, 다양한 속성을 손쉽게 관리할 수 있습니다.
- 사용자가 증가함에 따라 데이터도 급격히 증가할 수 있습니다. MongoDB는 샤딩(sharding)을 지원하여 수평적 확장이 용이합니다. 이를 통해 필요할 때 서버를 추가하여 데이터베이스의 성능을 높일 수 있습니다.
- 카카오 로그인 API에서 받은 사용자 정보는 다양한 필드를 가질 수 있습니다. MongoDB는 스키마가 필요 없거나 유연한 스키마를 지원하므로, 애플리케이션의 요구 사항이 변경되더라도 데이터베이스 구조를 쉽게 조정할 수 있습니다.
이러한 장점을 통해 Node.js와 MongoDB를 조합하여 비동기 처리에 강점을 가지는 개발 환경을 구성할 수 있습니다.
이는 개발자들이 빠르게 프로토타입을 만들고 개발할 수 있는 환경을 제공하여, 카카오 API기능을 빠르게 구현하고 테스트하는 데 유리합니다.
:: 시작하기 전에 ::
# 준비물 :
- Node.js 설치 및 Node.js를 실행할 수 있는 콘솔 환경
- MongoDB 설치 완료
- Visual Studio Code 등의 코드 편집기
# 주의사항 :
- Git을 사용한다면 ".gitignore"에 .env를 예외 등록하세요. ".env" 파일에는 JWT 비밀 키, 카카오 REST API키, 데이터베이스 주소가 포함됩니다.
// .gitignore 파일 작성
.env
1. Node.js와 필요한 패키지 설치
mkdir kakao-login-server // 프로젝트 폴더 생성
cd kakao-login-server // 생성한 폴더로 이동
// 터미널에 입력 (node.js와 npm이 설치되어있어야함)
npm init -y
npm install express mongoose axios dotenv jsonwebtoken cookie-parser
2. 환경 변수 설정 ( 아래쪽에 JWT 시크릿 키를 생성하는 법도 기재 해두었습니다 )
/* 루트 경로에서 .env 파일 생성, 내용 추가 */
KAKAO_CLIENT_ID=your_kakao_client_id // 카카오 REST API 키
REDIRECT_URI=your_redirect_uri // 카카오 리다이렉트 URI
MONGODB_URI=your_mongodb_uri // 몽고DB 주소
JWT_SECRET=your_jwt_secret // JWT 시크릿 키
PORT=3000 // 포트 : 3000 (기본값)
3. MongoDB 모델 생성
/*
MongoDB 모델 생성
models/User.js : models 폴더에 현재 코드 User.js를 작성합니다.
*/
const mongoose = require('mongoose');
// 사용자 스키마 정의
const userSchema = new mongoose.Schema({
kakaoId: {
type: String,
required: true,
unique: true, // 카카오 ID는 고유해야 함
},
email: {
type: String,
required: false, // 이메일 필드는 선택 사항 (카카오 디벨로퍼 설정 필요)
},
profile: {
type: String,
required: false, // 프로필 이미지 필드는 선택 사항 (카카오 디벨로퍼 설정 필요)
},
createdAt: {
type: Date,
default: Date.now, // 기본 생성일
},
});
// 사용자 모델 생성
const User = mongoose.model('User', userSchema);
module.exports = User;
4. 인증 서비스 작성
/*
인증 서비스 작성
services/authService.js : services폴더에 authService.js에 현재 코드를 작성합니다.
*/
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
// Mongoose 사용자 스키마 정의
const userSchema = new mongoose.Schema({
kakaoId: { type: String, required: true, unique: true } // 카카오 고유 ID
}, { timestamps: true }); // 생성 및 수정 시간을 자동으로 기록
const User = mongoose.model('User', userSchema); // 사용자 모델 생성
// 사용자 정보를 DB에 저장하는 함수
async function saveUser(userInfo) {
const kakaoId = userInfo.id;
const existingUser = await User.findOne({ kakaoId });
if (!existingUser) {
// 새 사용자 저장
const newUser = new User({
kakaoId,
email: userInfo.kakao_account.email
});
await newUser.save();
}
return kakaoId; // 사용자 ID 반환
}
// JWT 토큰 생성 함수
function generateToken(kakaoId) {
const token = jwt.sign({ id: kakaoId }, process.env.JWT_SECRET, {
expiresIn: '1h',
});
return token;
}
module.exports = {
saveUser,
generateToken,
User, // User 모델도 내보내기
};
5. Express 서버 설정
/*
Express 서버 설정
루트 경로에 index.js를 작성합니다.
*/
require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const axios = require('axios');
const cookieParser = require('cookie-parser');
const app = express();
const { saveUser, generateToken } = require('./services/authService'); // authService 임포트
const PORT = process.env.PORT || 3000;
app.use(cookieParser());
// 카카오 로그인 URL 생성 및 리다이렉션
app.get('/auth/kakao', (req, res) => {
const kakaoAuthUrl = `https://kauth.kakao.com/oauth/authorize?client_id=${process.env.KAKAO_CLIENT_ID}&redirect_uri=${process.env.REDIRECT_URI}&response_type=code&scope=account_email`;
res.redirect(kakaoAuthUrl);
});
// MongoDB 연결
mongoose.connect(process.env.MONGODB_URI)
.then(() => console.log('MongoDB connected'))
.catch(err => console.error('MongoDB connection error:', err));
// 카카오 콜백 라우트
app.get('/auth/kakao/callback', async (req, res) => {
const { code } = req.query;
try {
// 1. 인증 코드로 액세스 토큰 요청
const tokenResponse = await axios.post('https://kauth.kakao.com/oauth/token', null, {
params: {
grant_type: 'authorization_code',
client_id: process.env.KAKAO_CLIENT_ID,
redirect_uri: process.env.REDIRECT_URI,
code,
},
});
const { access_token } = tokenResponse.data;
// 2. 액세스 토큰으로 사용자 정보 요청
const userResponse = await axios.get('https://kapi.kakao.com/v2/user/me', {
headers: {
Authorization: `Bearer ${access_token}`,
},
});
const userInfo = userResponse.data;
const kakaoId = await saveUser(userInfo); // 사용자 정보 DB에 저장
const token = generateToken(kakaoId); // JWT 토큰 발급
res.cookie('token', token); // 쿠키에 저장
res.json({ token, userInfo }); // 사용자 정보 응답
} catch (error) {
console.error('카카오 로그인 실패:', error);
res.status(500).json({ message: '카카오 로그인 중 오류가 발생했습니다.' });
}
});
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
6. 서버 실행
// 서버 실행(터미널)
node index.js
7. 카카오 로그인 테스트
// 브라우저에서 카카오 로그인 시도
http://localhost:3000/auth/kakao
# .env의 JWT_SECRET= 항목에 들어갈 비밀 키 생성
# 생성된 키를 복사하여 사용합니다
/*
Node.js 명령어 :
64바이트의 랜덤 바이트를 생성하고, 16진수(hex)문자열로 변환하여 출력.
최종 128자리 16진수 문자열
*/
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
/*
OpenSSL 명령어 :
32바이트의 랜덤 바이트를 생성하고, 이를 16진수(hex) 문자열로 변환하여 출력.
최종 64자리 16진수 문자열
*/
openssl rand -hex 32
[ 실행 결과 ]
브라우저에서 'http://localhost:3000/auth/kakao' 로 접속했을 때
{
"token": "abcd1234",
"userInfo": {
"id": 00000000,
"connected_at": "2024-11-11T01:11:11Z",
"kakao_account": {
"has_email": true,
"email_needs_agreement": false,
"is_email_valid": true,
"is_email_verified": true,
"email": "abcd1234@email.com"
}
}
}
이런 형식의 JSON 문자열이 제대로 응답되었다면 성공입니다. 이 문자열은 방금 로그인한 유저정보입니다.
저는 파라미터로 email을 받도록 추가했기 때문에 email 관련 응답도 들어있습니다.
파라미터를 추가하려면 카카오 디벨로퍼에서도 추가할 요소에 체크해두어야 합니다.
MongoDB 연결이 제대로 되어있으면, 데이터가 [localhost:27017> myDatabase> users](예시)처럼 DB에 저장됩니다.
[ 후기 ]
Node.js서버와 MongoDB를 조합하고 JWT토큰을 사용하여 카카오 API 로그인을 구현해보았습니다.
Spring Boot에서는 애플리케이션의 처리 및 흐름을 설명하는 개념을 주로 "로직"이라는 용어를 사용해 비즈니스 로직을 강조했었는데,
Node.js에서는 "플로우"라는 용어를 사용해 비동기 처리 및 요청/응답 흐름을 강조하는 차이점이 있었습니다.
Node.js는 단일 스레드 비동기 처리 방식을 기반으로 설계되어 있어, "플로우"라는 개념이 중요해졌다고 합니다.
Node.js와 Express 프레임워크를 통해 빠르게 프로토타입을 만들 수 있었습니다.
MongoDB는 REST API의 응답 형식인 JSON 문자열을 유연하게 저장하고 데이터를 쉽게 관리할 수 있었습니다.
'API' 카테고리의 다른 글
스프링부트에서 페이팔 결제 API를 사용해보자 [PayPal/후기] (1) | 2024.10.28 |
---|---|
카카오 지도 Web API 사용해보기 [스프링부트/후기] (0) | 2024.10.22 |
스프링부트 카카오 로그인 버튼 구현하기 [REST API/후기] (3) | 2024.10.21 |