이번에는 Express.js를 이용해서 Backend를 구성해보도록 하겠습니다. Backend 서버는 Express지만,
그 외에도 추가로 MongoDB에 적당한 클러스터 생성이 필요합니다. 그리고 Kakao 로그인 연동을 위해 Kakao Developers
사이트에서 앱 생성이 필요합니다. 이부분은 많은 지문을 필요로 하는 부분이라 여기서 다루지는 않겠습니다.
1. 환경파일(.env) 생성
Backend 프로젝트 폴더에 .env 파일을 생성해서 비밀 환경정보 등을 저장합니다.
PORT=3000
NODE_ENV='development'
MONGO_URI='mongodb+srv://몽고디비ID:몽고디비PW@cluster0.juisc.mongodb.net/test'
KAKAO_ID=00sdfsdf6432sdfa792sdfssdfsdf28이거내가고친거임
KAKAO_REDIRECT_URI=http://localhost:3000/auth/kakao/callback
SECRET=mysecretkeytest
2. 패키지 설치
필요한 패키지들을 설치합니다. 설치할 땐 "npm i 패키지이름", 개발환경 의존성은 "npm i -D 패키지이름"
"dependencies": {
"body-parser": "^1.20.2",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"express-session": "^1.17.3",
"mongoose": "^7.0.4",
"passport": "^0.6.0",
"passport-local": "^1.0.0",
"passport-local-mongoose": "^8.0.0",
"pm2": "^5.3.0"
},
"devDependencies": {
"nodemon": "^2.0.22"
}
3. index.js
cors가 조금 문제스럽습니다. 아직도 정확히 작동하는 법은 몰라서 이것저것 남겨놓습니다.
라우팅은 포스팅 관련된 postRoute와 사용자관리 관련된 userRoute 두가지로 구성했습니다.
import express from 'express';
import session from 'express-session';
import cookieParser from 'cookie-parser';
import bodyParser from 'body-parser';
import dotenv from 'dotenv';
import mongoose from 'mongoose';
import postRoute from './routes/postRoute.js';
import userRoute from './routes/userRoute.js';
import cors from 'cors';
import path from 'path';
dotenv.config();
const app = express();
const __dirname = path.resolve();
const { PORT, MONGO_URI, SECRET } = process.env;
app.set('port', PORT || 3000);
mongoose.connect(MONGO_URI)
.then(() => {
console.log('Connected to MongoDB');
})
.catch(e => {
console.error(e);
});
app.use(express.static('public'));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser(SECRET));
app.use(session({
resave: false,
saveUninitialized: false,
secret: SECRET,
cookie: {
httpOnly: true,
secure: false
}
}));
// const options = {
// origin: "http://localhost:4000", // 접근 권한을 부여하는 도메인
// credentials: true, // 응답 헤더에 Access-Control-Allow-Credentials 추가
// optionsSuccessStatus: 200, // 응답 상태 200으로 설정
// };
// app.use(cors(options));
app.use(cors());
app.all('/*', function(req, res, next){
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
})
app.use('/posts',postRoute);
app.use('/auth',userRoute);
var router = express.Router();
app.get('/', function(req,res,next){
res.sendFile(path.join(__dirname, './public','index.html'))
})
app.listen(app.get('port'), ()=> {
console.log(`${app.get('port')}번 포트에서 서버 실행 중..`);
});
4. models/Post.js
포스트 모델을 구성합니다.
import mongoose from "mongoose";
let PostSchema = new mongoose.Schema({
title: String,
body: String,
publishedDate: Date,
creator: {
_id:{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String,
password:String,
email: String
},
});
let Post = mongoose.model("Post", PostSchema);
export default Post;
5. models/User.js
사용자 모델을 생성합니다.
import mongoose from 'mongoose';
import passportLocalMongoose from 'passport-local-mongoose'
let UserSchema = new mongoose.Schema({
username: String,
password:String,
email: String
});
UserSchema.plugin(passportLocalMongoose);
const User = mongoose.model("User", UserSchema);
export default User;
6. routes/postRoute.js
import express from 'express';
import Post from '../models/Post.js';
import User from '../models/User.js';
import bodyParser from 'body-parser'
const router = express.Router();
router.use(express.json());
// 전체 리스트 읽기
router.get('/', (req, res) => {
Post.find()
.then((post) =>{
res.send({post});
})
});
// 신규 포스트 생성
router.post('/', async (req, res) => {
const { title, body } = req.body;
// const creator = req.body.email;
console.log(req.body);
const post = new Post({
title,
body,
creator: req.body.creator,
});
try{
await post.save();
// console.log(post);
res.body = post;
res.send(post);
} catch (e) {
console.error(e);
}
});
// 특정 포스트 조회
router.get('/:id', async (req, res) => {
const { id } = req.params;
console.log(id);
try {
const post = await Post.findById(id).exec();
if(!post){
res.sendStatus(404);
return;
}
res.body = post;
res.send(post);
} catch (e) {
console.error(e);
}
});
// 특정 포스트 업데이트
router.patch('/:id', async (req, res) => {
const { id } = req.params;
// const { title, body } = req.body;
try{
const post = await Post.findByIdAndUpdate(id, req.body, {new:true,}).exec();
if(!post){
console.sendStatus(404);
return;
}
res.body = post;
res.send(post);
} catch(e){
console.error(e);
}
});
// 특정 포스트 삭제
router.delete('/:id', async (req, res) => {
const { id } = req.params;
// console.log(req.params);
try{
await Post.findByIdAndRemove(id).exec();
res.sendStatus(204);
} catch(e){
console.error(e);
}
});
export default router;
7. routes/userRoute.js
유저 인증은 passport-local 라이브러리를 이용한 방식으로 진행합니다. Front에서 Kakao로 인증하고, 사용자 정보를 Backend로 넘겨주면 처리합니다. 이때 URL은 '/register' 만 사용하는데, 등록된 사용자면 login을 시도하고 등록 안된 사용자면 신규로 user테이블에 생성합니다. 즉 무조건 가입/로그인 되는 방식입니다.
import express from 'express';
import User from '../models/User.js';
import passport from 'passport';
import Localstrategy from 'passport-local';
const router = express.Router();
passport.use(new Localstrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
router.use(passport.initialize());
router.use(passport.session());
const isLoggedIn = (req, res, next) => {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login');
};
router.post('/register', async (req, res, next) => {
const { username, email, password } = req.body;
try{
const existingUser = await User.findOne({ email });
// console.log(existingUser); //DB에서 존재하는 emial인지 확인
if (existingUser) {
// User already exists, redirect to login page or show error message
passport.authenticate('local')(req, res, () => {
// Authentication successful
// console.log(req.user);
console.log("Login success!");
return res.send(req.user);
});
} else {
const newUser = new User({ username, email });
await User.register(newUser,password); // 패스워드만 따로 보내야 해싱처리 등이 적용됨
passport.authenticate("local")(req, res, () => {
// console.log(req.user);
console.log("Success! You are registered and logged in!");
return res.send(req.user);
});
}
} catch (err) {
return next(err);
}
});
router.get('/protected', isLoggedIn, (req, res) => {
res.send('Protected content');
});
router.get("/logout", (req, res) => {
req.logout();
res.redirect("back");
});
export default router;
passport-kakao 라이브러리도 있는데, backend에서 구현하면 계속 cors문제를 해결 못했습니다. 그래서 front에서 인증하고, 사용자 정보를 backend로 넘기는 방식으로 구현함..ㅠㅠ
'Programming > Vue' 카테고리의 다른 글
서버리스 앱만들기 - 1. CockroachDB Serverless 데이터베이스 시작하기 (0) | 2023.05.18 |
---|---|
Vue todolist 만들기 - 8. Backend 연동을 위해 Frontend 수정하기 (0) | 2023.05.05 |
Vue todolist 만들기 - 6. Kakao 로그인 구현 (0) | 2023.05.04 |
Vue todolist 만들기 - 5. Post 수정기능 (0) | 2023.05.04 |
Vue todolist 만들기 - 4. Store 적용하기...Post추가/삭제 (0) | 2023.05.04 |