실시간 경매 시스템 만들기 - 프로젝트 구조 갖추기(2)
모델을 생성한 후에 모델을 데이터베이스 및 서버와 연결합니다. nodeauction 데이터베이스를 생성해야 하므로 config.json을 데이터베이스에 맞게 수정합니다.
config/config.json
{
"development": {
"username": "root",
"password": "1234",
"database": "nodeauction",
"host": "127.0.0.1",
"dialect": "mysql"
},
"test": {
"username": "root",
"password": "1234",
"database": "nodeauction_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": "1234",
"database": "nodeauction_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
npx sequelize db:create 명령어로 데이터베이스를 생성합니다.
$ npx sequelize db:create
models/index.js를 다음과 같이 바꿉니다.
const Sequelize = require("sequelize");
const User = require("./user");
const Good = require("./good");
const Auction = require("./auction");
const env = process.env.NODE_ENV || "development";
const config = require("../config/config")[env];
const db = {};
const sequelize = new Sequelize(
config.database,
config.username,
config.password,
config,
);
db.sequelize = sequelize;
db.User = User;
db.Good = Good;
db.Auction = Auction;
User.init(sequelize);
Good.init(sequelize);
Auction.init(sequelize);
User.associate(db);
Good.associate(db);
Auction.associate(db);
module.exports = db;
이제 로그인을 위한 패스포트 설정이 필요합니다. 이번에는 단순히 passport-local만 사용하겠습니다.
$ npm i passport passport-local bcrypt
passport/localStrategy.js
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");
const User = require("../models/user");
module.exports = () => {
passport.use(
new LocalStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
const exUser = await User.findOne({ where: { email } });
if (exUser) {
const result = await bcrypt.compare(password, exUser.password);
if (result) {
done(null, exUser);
} else {
done(null, false, { message: "비밀번호가 일치하지 않습니다." });
}
} else {
done(null, false, { message: "가입되지 않은 회원입니다." });
}
} catch (error) {
console.error(error);
done(error);
}
},
),
);
};
passport/index.js
const passport = require("passport");
const local = require("./localStrategy");
const User = require("../models/user");
module.exports = () => {
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findOne({ where: { id } })
.then((user) => done(null, user))
.catch((err) => done(err));
});
local();
};
로그인을 위한 라우터와 미들웨어도 추가합니다.
const express = require('express');
const passport = require('passport');
const bcrypt = require('bcrypt');
const { isLoggedIn, isNotLoggedIn } = require('./middlewares');
const User = require('../models/user');
const router = express.Router();
router.post('/join', isNotLoggedIn, async (req, res, next) => {
const { email, nick, password, money } = req.body;
try {
const exUser = await User.findOne({ where: { email } });
if (exUser) {
return res.redirect('/join?joinError=이미 가입된 이메일입니다.');
}
const hash = await bcrypt.hash(password, 12);
await User.create({
email,
nick,
password: hash,
money,
});
return res.redirect('/');
} catch (error) {
console.error(error);
return next(error);
}
});
router.post('/login', isNotLoggedIn, (req, res, next) => {
passport.authenticate('local', (authError, user, info) => {
if (authError) {
console.error(authError);
return next(authError);
}
if (!user) {
return res.redirect(`/?loginError=${info.message}`);
}
return req.login(user, (loginError) => {
if (loginError) {
console.error(loginError);
return next(loginError);
}
return res.redirect('/');
});
})(req, res, next);
});
router.get('/logout', isLoggedIn, (req, res) => {
req.logout();
req.session.destroy();
res.redirect('/');
});
module.exports = router;
routes/middlewares.js
exports.isLoggedIn = (req, res, next) => {
if (req.isAuthenticated()) {
next();
} else {
res.redirect("/?loginError=로그인이 필요합니다.");
}
};
exports.isNotLoggedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
next();
} else {
res.redirect("/");
}
};
마지막으로 .env 파일과 서버 코드를 작성합니다. 시퀄라이즈와 패스포트를 모두 서버에 연결합니다.
COOKIE_SECRET=auction
app.js
const express = require('express');
const path = require('path');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const passport = require('passport');
const nunjucks = require('nunjucks');
const dotenv = require('dotenv');
dotenv.config();
const indexRouter = require('./routes/index');
const authRouter = require('./routes/auth');
const { sequelize } = require('./models');
const passportConfig = require('./passport');
const app = express();
passportConfig();
app.set('port', process.env.PORT || 8010);
app.set('view engine', 'html');
nunjucks.configure('views', {
express: app,
watch: true,
});
sequelize.sync({ force: false })
.then(() => {
console.log('데이터베이스 연결 성공');
})
.catch((err) => {
console.error(err);
});
const sessionMiddleware = session({
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
});
app.use(morgan('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/img', express.static(path.join(__dirname, 'uploads')));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(sessionMiddleware);
app.use(passport.initialize());
app.use(passport.session());
app.use('/', indexRouter);
app.use('/auth', authRouter);
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
error.status = 404;
next(error);
});
app.use((err, req, res, next) => {
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== 'production' ? err : {};
res.status(err.status || 500);
res.render('error');
});
app.listen(app.get('port'), () => {
console.log(app.get('port'), '번 포트에서 대기중');
});
경매 시스템은 회원가입, 로그인, 경매 상품 등록, 방 참여, 경매 진행으로 이루어져 있습니다. 회원가입, 로그인, 경매 상품 등록 페이지와 라우터를 만들어보겠습니다.
'프로그래밍 언어 > NODE JS' 카테고리의 다른 글
| 실시간 경매 시스템 만들기 - 서버센트 이벤트 사용하기(1) (0) | 2026.02.23 |
|---|---|
| 실시간 경매 시스템 만들기 - 프로젝트 구조 갖추기(3) (0) | 2026.02.20 |
| 실시간 경매 시스템 만들기 - 프로젝트 구조 갖추기(1) (0) | 2026.02.13 |
| 프로젝트 마무리하기 (0) | 2026.02.10 |
| 채팅 구현하기 (0) | 2026.02.07 |