728x90
๋ฐ์ํ
๐ก ์ค์ต ํฌ์ธํธ!
๐ ๋ก๊ทธ์ธ ์ฑ๊ณต
๐ ๋ก๊ทธ์ธ ์คํจ
- ๋๊ตฐ๊ฐ๊ฐ ๋ก๊ทธ์ธ์ ํ๋ฉด ๊ทธ ์ฌ๋์ ์์ด๋์ ๋น๋ฐ๋ฒํธ๊ฐ DB ์ ์๋ ์์ด๋์ ๋น๋ฐ๋ฒํธ๊ฐ ๋ง๋์ง ๊ฒ์ฌํ๋ ๊ณผ์ ์ ๊ฑฐ์น๋ค.
- ๊ฒ์ฌ ๊ฒฐ๊ณผ ์ผ์นํ๋ค๋ฉด, ์ธ์ ์ ํ๋ ์์ฑํ๊ณ ์ฑ๊ณตํ์ด์ง๋ก ์ด๋ํ๋ค.
- ๊ฒ์ฌ ๊ฒฐ๊ณผ ํด๋นํ๋ ์์ด๋๊ฐ ์กด์ฌํ์ง ์๊ฑฐ๋, ๋น๋ฐ๋ฒํธ๊ฐ ํ๋ ธ๋ค๋ฉด ์คํจํ์ด์ง๋ก ์ด๋ํ๋ค.
(/fail ๊ฒฝ๋ก์ ๋ณ๋์ EJS ํ์ผ์ด๋ HTML ํ์ผ์ ๋ง๋ค์ด๋์ง๋ ์์๋ค.)
๐ ๋ก๊ทธ์ธ ํ์ด์ง ๋ง๋ค๊ธฐ & ์์ด๋ ๋น๋ฒ ๊ฒ์ฌํ๊ธฐ
๐ค ์ค๋นํ๊ธฐ
- ํฐ๋ฏธ๋์ npm install passport passport-local express-session ์ ์ ๋ ฅํ์ฌ ๋ก๊ทธ์ธ ๋ฐ ์ธ์ ์์ฑ์ ๋์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ 3๊ฐ(๋ก๊ทธ์ธ, ๋ก๊ทธ์ธ ๊ฒ์ฆ, ์ธ์ ์์ฑ)๋ฅผ ์ค์นํ๋ค.
- ์ค์น๊ฐ ์๋ฃ๋๋ฉด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ๋ฒ์ ๋ฐ๋ผ JavaScript ํ์ผ ์๋จ์ ์๋์ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํ๋ค.
const passport = require('passport');
const localStrategy = require('passport-local').Strategy; // ์ธ์ฆํ๋ ๋ฐฉ๋ฒ์ Strategy ๋ผ๊ณ ์ง์นญํ๋ค.
const session = require('express-session');
app.use(session({secret : '๋น๋ฐ์ฝ๋', resave : true, saveUninitialized : false}));
app.use(passport.initialize());
app.use(passport.session());
- app.use() ํจ์๋ ๋ฏธ๋ค์จ์ด(์์ฒญ๊ณผ ์๋ต์ฌ์ด์ ํน์ ํ ๊ฒ์ ์คํ์ํค๋ ์ฝ๋)๋ฅผ ์ฌ์ฉํ๊ฒ ๋ค๋ ์๋ฏธ๋ก ์์ ์ฝ๋ ๋ด์ฉ ์ค passport.initialize() ๋ passport.session() ๊ณผ ๊ฐ์ ์ฝ๋๊ฐ ๋ชจ๋ ์์ฒญ๊ณผ ์๋ต ์ค๊ฐ์ ์คํ๋ ์์ ์ธ ๋ฏธ๋ค์จ์ด์ ํด๋นํ๋ค.
๐ค ๋ก๊ทธ์ธ ํ์ด์ง ๋ง๋ค๊ณ ๋ผ์ฐํ ํ๊ธฐ
- ๊ธ์ฐ๊ธฐ ํ์ด์ง์ ์ ์ฌํ ๋ ์ด์์์ผ๋ก ๋ก๊ทธ์ธ ํ์ด์ง์ฉ EJS ํ์ผ์ ๋ง๋ค๊ณ , /login ๊ฒฝ๋ก๋ก ๋ค์ด์์ ๋ ๋ก๊ทธ์ธ ํ์ด์ง๊ฐ ๋ธ๋ผ์ฐ์ ์ ๋ณด์ผ ์ ์๊ฒ ํด์ฃผ์๋ค.
- ๊ทธ ์ธ input ์ ์์ฑ์ธ name ๊ณผ action ์ ๊ฒฝ๋ก ๋ฑ์ ์กฐ๊ธ ์์ ํ์๋ค.
<h4 class="container mt-5"><strong>๋ก๊ทธ์ธ</strong></h4>
<div class="container mt-4">
<form action="/login" method="POST">
<div class="form-group my-4">
<label class="mb-2">์์ด๋</label>
<input type="text" class="form-control" name="id">
</div>
<div class="form-group my-4">
<label class="mb-2">๋น๋ฐ๋ฒํธ</label>
<input type="password" class="form-control" name="pw">
</div>
<button type="submit" class="btn btn-danger fw-bold">Submit</button>
</form>
</div>
- ๋ก๊ทธ์ธ ํ์ด์ง๋ฅผ ๋ง๋ค์์ผ๋ ์ด์ /login ๊ฒฝ๋ก๋ก ์ ์ํ์ ๋ ์ด ๋ก๊ทธ์ธ ํ์ด์ง๊ฐ ๋ณด์ด๋๋ก JavaScript ์ฝ๋๋ฅผ ์์ฑํ๋ค.
app.get('/login', function(req, res){
res.render('login.ejs');
})
๐ ํ ์คํธ์ฉ ์์ด๋์ ๋น๋ฐ๋ฒํธ ์์ฑํ๊ธฐ
- ์ด์ ๋ก๊ทธ์ธํ ์์ด๋์ ๋น๋ฐ๋ฒํธ๊ฐ ํ์ํ๋ฐ, ํ์๊ฐ์ ํ์ด์ง ๋ฐ ๊ธฐ๋ฅ ๊ตฌํ์ ์งํํ์ง ์๋๋ค๊ณ ํด์ ์๋์ ๊ฐ์ด DB ์ login collection ์ ์์ฑํด์ ์์ด๋์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ง์ ๋ง๋ค์ด์ฃผ์๋ค.
๐ค ๋ก๊ทธ์ธ ํ์ด์ง์์ ๋ก๊ทธ์ธ ์ ์์ด๋, ๋น๋ฐ๋ฒํธ ๊ฒ์ฌํ๊ธฐ
- ๋๊ตฐ๊ฐ๊ฐ ๋ก๊ทธ์ธ ํ์ด์ง์์ ์์ด๋์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ๋ ฅํ ํ Submit ๋ฒํผ์ ๋๋ฌ POST ์์ฒญ์ ํ๋ฉด, ์์ด๋์ ๋น๋ฐ๋ฒํธ๊ฐ DB ์ ๋ฐ์ดํฐ์ ์ผ์นํ๋์ง ๊ฒ์ฌํ๋ ์ฝ๋๋ฅผ JavaScript ํ์ผ์ ์์ฑํด์ฃผ์๋ค.
app.post('/login', passport.authenticate('local', {
failureRedirect : '/fail' // login ์ ์คํจํ๋ฉด /fail ๊ฒฝ๋ก๋ก ์ด๋ํ๋ค.
}), function(req, res){
res.redirect('/'); // login ์ ์ฑ๊ณตํ๋ฉด / ๊ฒฝ๋ก๋ก ์ด๋ํ๋ค.
})
- ๋๊ตฐ๊ฐ๊ฐ /login ๊ฒฝ๋ก๋ก POST ์์ฒญ์ ํ๋ฉด, ์ค๊ฐ์ ์์ด๋์ ๋น๋ฐ๋ฒํธ๊ฐ DB ์ ์๋ ๋ฐ์ดํฐ์ ์ผ์นํ๋์ง ๊ฒ์ฌํ๊ณ ์ด ๊ณผ์ ์์ ์คํจํ๋ฉด /fail ๊ฒฝ๋ก๋ก ์ด๋ํ๊ณ ์ฑ๊ณตํ๋ฉด / ๊ฒฝ๋ก(ํ)์ผ๋ก ์ด๋ํ๋๋ก ํด์ฃผ์๋ค.
- post() ํจ์์ ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก passport ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ ๊ณตํ๋ ์ฝ๋(์์ด๋์ ๋น๋ฐ๋ฒํธ๊ฐ DB ์ ์๋ ๋ฐ์ดํฐ์ ์ผ์นํ๋์ง ๊ฒ์ฌ)๋ฅผ ๋ฃ์ด์ฃผ์ด, ์๋ตํ๊ธฐ ์ ์ local ๋ฐฉ์์ผ๋ก ์ธ์ฆํ๋๋ก ํ๋ค.
- failuerRedirect : '/fail' ๋ถ๋ถ์ ๋ก๊ทธ์ธ ์ธ์ฆ ์คํจํ๋ ๊ฒฝ์ฐ /fail ๊ฒฝ๋ก๋ก ์ด๋ํ๋๋ก ํด์ฃผ๋ ์ฝ๋์ด๋ค.
๐ ์์ด๋์ ๋น๋ฐ๋ฒํธ DB ์ ๋ฐ์ดํฐ์ ๋น๊ตํ๊ณ ์ธ์ ๋ง๋ค์ด์ฃผ๊ธฐ
๐ค ์์ด๋ ๋ฐ ๋น๋ฐ๋ฒํธ๊ฐ DB ์ ๋ฐ์ดํฐ์ ์ผ์นํ๋์ง ๋น๊ตํ๊ธฐ
- ๋๋ต ์๋์ฝ๋๋ฅผ ๊ตฌ์ฑํ์๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
- ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ์์ด๋์ ๋น๋ฐ๋ฒํธ๋ฅผ inputId, inputPw ๋ผ๋ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ๋๋ค.
- DB ์์ { id : inputId } ์ธ ๋ฐ์ดํฐ๋ฅผ ์ฐพ๋๋ค.
- ๋ง์ฝ ํด๋นํ๋ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด inputPw ์ ๋ฐ์ดํฐ์ pw ๊ฐ ์ผ์นํ๋์ง ํ์ธํ๋ค.
- ์ผ๋ จ์ ๊ณผ์ ์ด ์ฑ๊ณตํ๋ค๋ฉด return done(null, result) ๋ฅผ ์คํํ๋ค.
- ์๋์ฝ๋๋ฅผ JavaScript ํ์ผ์ ์ฝ๋๋ก ๋ด์๋ด์๋ฉด ์๋์ ๊ฐ๋ค.
passport.use(new localStrategy({
usernameField : 'id', // name ์ด id ์ธ input ์ด usernameField ์ด๋ค.
passwordField : 'pw', // name ์ด pw ์ธ input ์ด passwordField ์ด๋ค.
session : true, // session ์ ๋ณด๋ฅผ ์ ์ฅํ๋ค.
passReqToCallback : false, // ์์ด๋,๋น๋ฐ๋ฒํธ ์ธ ๋ค๋ฅธ ์ ๋ณด๋ฅผ ๊ฒ์ฆํ ๊ฒฝ์ฐ true ๋ก ์์ฑ, ์ฝ๋ฐฑํจ์์ req ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฃ์ด์ค๋ค.
}, function(inputId, inputPw, done){
//console.log(inputId, inputPw); // ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ์์ด๋, ๋น๋ฐ๋ฒํธ ํ์ธ
// db.collection ์ค login ์์ id ๊ฐ inputId ์ ์ผ์นํ๋ ๋ฐ์ดํฐ๋ฅผ ์ฐพ์ผ๋ฉด
db.collection('login').findOne({id : inputId}, function(err, result){
if (err) return done(err);
// result ์ ์๋ฌด๋ฐ ๊ฐ์ด ๋ด๊ฒจ์์ง ์๋ค๋ฉด(DB ์ ์์ด๋๊ฐ ์์ผ๋ฉด)
if (!result) return done(null, false, {message : '์กด์ฌํ์ง ์๋ ์์ด๋์
๋๋ค.'});
// result ์ ๊ฐ์ด ๋ด๊ฒจ ์๋ค๋ฉด(DB ์ ์์ด๋๊ฐ ์๋ค๋ฉด)
// inputPw ์ result ์ ๋ด๊ฒจ์๋ pw ๊ฐ ์ผ์นํ๋์ง ํ์ธํ๊ธฐ
if (inputPw == result.pw) {
return done(null, result);
} else {
return done(null, false, {message : '๋น๋ฐ๋ฒํธ๊ฐ ๋ค๋ฆ
๋๋ค.'})
}
})
}));
- ๋ค๋ง, ์์ ์ฝ๋๋ ์ ๋ฐ์ ์ธ ์ดํด๋ฅผ ์ํด DB ์ ์ ์ฅํ ๋น๋ฐ๋ฒํธ๋ ์ ๋ ฅํ ๋น๋ฐ๋ฒํธ๋ ์ํธํ๋ฅผ ์งํํ์ง ์๊ณ ๋น๊ตํ ๊ฒ์ด๋ฏ๋ก ๋ณด์๋ถ๋ถ์ ์กฐ๊ธ ๋ ๊ณต๋ถํ ๋ค์ ๋ณด์์ด ํ์ํ๋ค.
๐ค ์ธ์ ์ ๋ง๋ ํ, ์ธ์ ์์ด๋๋ฅผ ๋ฐ๊ธํ์ฌ ์ฟ ํค๋ก ๋ณด๋ด์ฃผ๊ธฐ
- ์์ด๋์ ๋น๋ฐ๋ฒํธ๊ฐ DB ์ ๋ฐ์ดํฐ์ ์ผ์นํ๋ค๋ฉด ์ธ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ธํ ํ ์ฟ ํค๋ก ๋ง๋ค์ด ์ฌ์ฉ์์๊ฒ ๋ณด๋ด์ฃผ์ด์ผ ํ๋ค.
// id ๋ฅผ ์ด์ฉํ์ฌ ์ธ์
์ ์ฅ ๋ฐ ์ฟ ํค ๋ฐํ (๋ก๊ทธ์ธ ์ฑ๊ณต ์)
passport.serializeUser(function(user, done){
done(null, user.id);
});
- serializeUser() ํจ์๋ ์ฌ์ฉ์์ id ๋ฐ์ดํฐ๋ฅผ ๋ฐํ์ผ๋ก ์ธ์ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๊ณ , ๊ทธ ์ธ์ ๋ฐ์ดํฐ์ ์์ด๋๋ฅผ ์ฟ ํค๋ก ๋ง๋ค์ด์ ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ๋ก ๋ณด๋ธ๋ค.
๐ ์์ฑ๋ ์ฟ ํค ํ์ธํ๊ธฐ
- ์ ์์ ์ธ ์์ด๋์ ๋น๋ฐ๋ฒํธ๋ก ๋ก๊ทธ์ธํ์ ๋, ์ฟ ํค๊ฐ ์์ฑ๋๋ ๊ณผ์ ์ GIF ๋ก ๋ง๋ค์ด๋ณด์๋ค.
- localhost:8080 ์ผ๋ก ์ ์ ํ ๊ฐ๋ฐ์๋๊ตฌ(F12 ํน์ ๋ง์ฐ์ค์ฐํด๋ฆญ-๊ฒ์ฌ)๋ก ๋ค์ด๊ฐ์ Application ํญ์ ํด๋ฆญํ๋ฉด ์๋์ ๊ฐ์ ํ๋ฉด์ด ๋์จ๋ค.
- ์ฌ๊ธฐ์ ์ข์ธก Cookies ๋ถ๋ถ์ http://localhost:8080 ์ ํด๋ฆญํ๋ฉด ์ ์ฅ๋ ์ฟ ํค๋ฅผ ํ์ธํ ์ ์๋๋ฐ, ์์ ๊ฐ์ด ๋ก๊ทธ์ธ ์ฑ๊ณต์ session ์ด๋ผ๊ณ ์ ํ ์ฟ ํค๊ฐ ์์ฑ๋๋ค.
๐ ๋ก๊ทธ์ธํ ์ฌ์ฉ์๋ง ์ ์ ๊ฐ๋ฅํ ํ์ด์ง ๋ง๋ค๊ธฐ
๐ค ๋ง์ดํ์ด์ง ๋ง๋ค๊ณ ๋ผ์ฐํ ํ๊ธฐ
<h4 class="container mt-5"><strong>๋ง์ดํ์ด์ง</strong></h4>
<div class="container mt-4">
</div>
- ๋ก๊ทธ์ธํ ์ฌ์ฉ์๋ง ์ ์ ๊ฐ๋ฅํ ๋ง์ดํ์ด์ง๋ฅผ EJS ํ์ผ๋ก ๋ง๋ค์ด์ฃผ์๋ค.
app.get('/mypage', function(req, res){
res.render('mypage.ejs');
})
- ์ด์ JavaScript ํ์ผ์์ /mypage ๊ฒฝ๋ก์ ์ ์ํ๋ ๊ฒฝ์ฐ ๋ง์ดํ์ด์ง๊ฐ ๋ธ๋ผ์ฐ์ ์ ๋ณด์ด๋๋ก ์ค์ ํด์ฃผ์๋ค.
๐ค ๋ก๊ทธ์ธํ ์ฌ๋๋ง ๋ง์ดํ์ด์ง ๋ณด์ฌ์ฃผ๊ธฐ
- ์์ ๊ณผ์ ๊น์ง๋ง ์งํํ๋ฉด ๋๊ตฌ๋ ์ง ๋ง์ดํ์ด์ง์ ์ ์์ด ๊ฐ๋ฅํ๋ฏ๋ก, ๋ก๊ทธ์ธํ ์ฌ์ฉ์๋ง ์ด ํ์ด์ง๋ฅผ ๋ณผ ์ ์๋๋ก ๋ฏธ๋ค์จ์ด๋ฅผ ํ๋ ์ถ๊ฐํ๋ค.
- ๋ฏธ๋ค์จ์ด๋ ๋๊ตฐ๊ฐ๊ฐ /mypage ์ ์ ์์ ์๋ํ๋ ๊ฒฝ์ฐ ์๋ตํ๊ธฐ ์ ์ ๋ก๊ทธ์ธ์ ํ๋์ง ํ์ธํ๋ ์ญํ ์ ์ํํด์ผ ํ๋ค.
app.get('/mypage', doLogin, function(req, res){
// console.log(req.user)
res.render('mypage.ejs', {user : req.user});
})
function doLogin(req, res, next){
// ๋ก๊ทธ์ธ์ ํ ์ํ๋ผ๋ฉด
if (req.user){
next(); // ํต๊ณผํ๋ค.
} else {
res.send("๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค.");
}
}
- ๊ทธ๋์ ์ด์ ์ ์์ฑํ๋ ์ฝ๋๋ฅผ ๋ฏธ๋ค์จ์ด๋ฅผ ์ถ๊ฐํ์ฌ ์กฐ๊ธ ์์ ํด์ฃผ์๋ค.
- doLogin ์ด๋ผ๋ ๋ฏธ๋ค์จ์ด๋ฅผ ๋ง๋ค์ด์, ๋ก๊ทธ์ธ์ ํ ์ํ๋ผ๋ฉด ํต๊ณผํ์ฌ ์ฝ๋ฐฑํจ์๋ฅผ ์คํํ๋๋ก ํ๊ณ ๋ก๊ทธ์ธ์ ํ์ง ์์ ์ํ๋ผ๋ฉด '๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค.' ๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ๋จ๋๋ก ํด์ฃผ์๋ค.
๐ค req.user ๋ถ์ํ๊ธฐ
- req.user ๋ ๋ก๊ทธ์ธํ ์ฌ์ฉ์์ DB ์ ์ ๋ณด(์์ด๋, ๋น๋ฐ๋ฒํธ, ์ฌ์ฉ์๋ช ๋ฑ)๋ฅผ ์๋ฏธํ๋๋ฐ ๊ทธ๋ฅ์ ์ถ๋ ฅ์ด ๋์ง ์๋๋ค.
- ์ด๋ฌํ ์ ๋ณด๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์ธ์ ์์ด๋๋ฅผ ๋ฐํ์ผ๋ก ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ์ฐพ๋ deserializeUser() ํจ์์ ๋ถ๋ถ ๊ธฐ๋ฅ ๊ฐ๋ฐ์ด ํ์ํ๋ค.
// ํน์ ์ธ์
๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง ์ฌ๋์ DB ์์ ๊ฒ์ (๋ง์ดํ์ด์ง ์ ์ ์)
passport.deserializeUser(function(userId, done){
// DB ์์ user.id ๋ก ์ฌ์ฉ์๋ฅผ ๊ฒ์ํ ํ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฐพ์์ ์ ์กํ๋ค.
db.collection('login').findOne({id : userId}, function(err, result){
done(null, result);
})
});
- deserializeUser() ํจ์๋ฅผ ์์ ๊ฐ์ด ์์ฑํ๊ฒ ๋๋ฉด DB ์์ { id : userId } ์ธ ๊ฒ์๋ฌผ์ ์ฐพ์์ ๊ฒฐ๊ณผ๋ฅผ result ๋ก ๋ฐ๊ฒ ๋๋ค.
- ๊ทธ๋ฌ๋ฉด ์ด result ์ ๋ด๊ธด ๋ฐ์ดํฐ๋ค์ req.user ๋ก ์ ๋ฌ์ด ๋๋ฏ๋ก ๋ก๊ทธ์ธํ ์ฌ์ฉ์์ DB ์ ์ ๋ณด๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
๐ค ๋ง์ด ํ์ด์ง์ ์ ์ํ ์ฌ์ฉ์์ ์ด๋ฆ์ ๋ธ๋ผ์ฐ์ ์ ๋ณด์ฌ์ฃผ๊ธฐ
app.get('/mypage', doLogin, function(req, res){
// console.log(req.user)
res.render('mypage.ejs', {user : req.user});
})
- ์ด์ ์ ๋ก๊ทธ์ธํ ์ฌ์ฉ์์ DB ์์ ์ ๋ณด๋ฅผ req.user ์ ๋ด์๋์์ผ๋, /mypage ๊ฒฝ๋ก๋ก ์ ์ํ์ฌ ํ์ด์ง๊ฐ ๋ ๋๋ง๋ ๋ ํด๋น ๋ฐ์ดํฐ๋ฅผ user ๋ผ๋ ๋ณ์์ ๋ด์ ์ ์กํด์ค๋ค.
<h4 class="container mt-5"><strong><%= user.id %> ๋์ ํ์ด์ง</strong></h4>
<div class="container mt-4">
</div>
- ์ด์ ๋ ํด๋นํ๋ EJS ํ์ผ์์ user ๋ผ๋ ๋ณ์๋ฅผ EJS ๋ฌธ๋ฒ์ผ๋ก ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
728x90
๋ฐ์ํ
'[๊ฐ๋ฐ] Practice > Node.js MongoDB' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Node.js / MongoDB] ํ์ ๊ธฐ๋ฅ์ ํฌํจํ ๊ฒ์ํ ๊ธฐ๋ฅ ๋ง๋ค๊ธฐ (0) | 2022.03.15 |
---|---|
[Node.js / MongoDB] ๊ฒ์ ๊ธฐ๋ฅ ๋ง๋ค๊ธฐ (1) | 2022.03.14 |
[Node.js / MongoDB] ๊ธ ์์ ๊ธฐ๋ฅ ๋ง๋ค๊ธฐ (0) | 2022.03.12 |
[Node.js / MongoDB] ์์ธ ํ์ด์ง ๋ง๋ค๊ธฐ (0) | 2022.03.12 |
[Node.js / MongoDB] AJAX ๋ก ์ญ์ ์์ฒญํ๊ธฐ (0) | 2022.03.12 |