๐ ์ฐธ๊ณ ๊ฐ์
[๋ฌด๋ฃ] ๋ฐ๋ผํ๋ฉฐ ๋ฐฐ์ฐ๋ ๋ ธ๋, ๋ฆฌ์กํธ ์๋ฆฌ์ฆ - ๊ธฐ๋ณธ ๊ฐ์ - ์ธํ๋ฐ | ๊ฐ์
์ด ๊ฐ์๋ฅผ ํตํด์ ๋ฆฌ์กํธ์ ๋ ธ๋๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ๊ธฐ๋ณธ์ ์ธ ๋ด์ฉ๋ค์ ๋ฐฐ์ธ ์ ์์ต๋๋ค., - ๊ฐ์ ์๊ฐ | ์ธํ๋ฐ...
www.inflearn.com
๐ฃ๋ก๊ทธ์ธ ๊ธฐ๋ฅ
Node.js
Express JS : ์น์ฌ์ดํธ, ์ดํ๋ฆฌ์ผ์ด์
์ ์ฝ๊ฒ ๋ง๋ค ์ ์๊ฒ ๋์์ค, framework for Node.js
index.js : ๋ฐฑ์๋ ์์์
Express "Hello World" example
Hello world example Embedded below is essentially the simplest Express app you can create. It is a single file app — not what you’d get if you use the Express generator, which creates the scaffolding for a full app with numerous JavaScript files, Jade
expressjs.com
mongoDB
MongoDB Atlas Database | Multi-Cloud Database Service
The multi-cloud database service at the heart of our application data platform that accelerates and simplifies how you build with data. Try MongoDB Atlas today!
www.mongodb.com
Mongoose : ๋ชฝ๊ณ DB๋ฅผ ํธํ๊ฒ ์ธ ์ ์๋ Object Modeling Tool
๐์๋ฌ ํด๊ฒฐ๋ฒ
MongoParseError: options usecreateindex, usefindandmodify are not supported
MongoParseError: options usecreateindex, usefindandmodify are not supported ์๋ฌ
Nodejs์์ mongoDB์ ์ฐ๊ฒฐ ์ ๋ค์๊ณผ ๊ฐ์ ์๋ฌ๊ฐ ๋ํ๋ฌ๋ค. MongoParseError: options usecreatein...
blog.naver.com
Model : Schema๋ฅผ ๊ฐ์ธ๋ ์ญํ
Git is the tool, GitHub is the service for projects that use Git
.gitignore ํ์ผ : git์์ ๊ด๋ฆฌํ ํ์์๋ ํ์ผ๋ค ์ ์ธํ๊ธฐ, ์ปค๋ฐ ์ ์ ์ธ
SSH : Secure Shell
#body parser ๋ค์ด๋ฐ๊ธฐ
npm install body-parser --save
POST MAN ๋ค์ด
Download Postman | Get Started for Free
Try Postman for free! Join 20 million developers who rely on Postman, the collaboration platform for API development. Create better APIs—faster.
www.postman.com
#Node Mon ๋ค์ด๋ก๋
npm install nodemon --save-dev
-dev : development ๋ชจ๋๋ฅผ ์๋ฏธ
#Bcrypt
Bcrypt ์ด์ฉํด์ ๋น๋ฐ ๋ฒํธ ์ํธํ ํด์ค > ๋ฐ์ดํฐ ๋ฒ ์ด์ค์ ์ ์ฅ
npm install bcrypt --save
#Bcrypt๋ก ๋น๋ฐ๋ฒํธ ์ํธํ ํ๋ ์์
Register Route๋ก ๊ฐ๊ธฐ
์ ์ ์ ๋ณด๋ค(Account, Password ๋ฑ)์ ๋ฐ์ดํฐ ๋ฒ ์ด์ค์ ์ ์ฅํ๊ธฐ ์ ์๊ฐ ์ํธํ ํ ํ์ด๋ฐ
-user model์ ์ ์ฅํ๊ธฐ ์ ์ ์ํ
User.js > saltRounds = salt๊ฐ ๋ช ๊ธ์์ธ์ง > salt ๋จผ์ ์์ฑ > salt๋ฅผ ์ด์ฉํด์ ๋น๋ฐ๋ฒํธ ์ํธํ
const bcrypt = require('bcrypt');
const saltRounds = 10
userSchema.pre('save', function( next ){
var user = this;
if(user.isModified('password')){ // ์ฌ์ฉ์๊ฐ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐ๊ฟ ๋๋ง ๋น๋ฐ๋ฒํธ ์ํธํ์ํค๊ธฐ
// ๋น๋ฐ๋ฒํธ ์ํธํ ์ํค๊ธฐ
bcrypt.genSalt(saltRounds, function(err, salt) {
if(err) return next(err)
bcrypt.hash(user.password, salt, function(err, hash){
if(err) return next(err)
user.password = hash
next()
})
});
} else{ // ๋น๋ฐ๋ฒํธ๊ฐ ์๋ ๋ค๋ฅธ ์ ๋ณด๋ฅผ ๋ฐ๊ฟ ๊ฒฝ์ฐ์๋ ๊ทธ๋ฅ next()๋ก ์ด๋
next()
}
});
bcrypt
A bcrypt library for NodeJS.. Latest version: 5.0.1, last published: a year ago. Start using bcrypt in your project by running `npm i bcrypt`. There are 3389 other projects in the npm registry using bcrypt.
www.npmjs.com
๋ชฝ๊ณ db > view monitoring > collections > password๊ฐ ์ํธํ๋ ๊ฑธ ํ์ธ ๊ฐ๋ฅ
#login route ๋ง๋ค๊ธฐ
1. ๋ฐ์ดํฐ ๋ฒ ์ด์ค์์ ์์ฒญํ email ์ฐพ๊ธฐ > User.findOne()
2. ๋ฐ์ดํฐ ๋ฒ ์ด์ค์์ ์์ฒญํ email์ด ์๋ค๋ฉด ๋น๋ฐ๋ฒํธ๊ฐ ๊ฐ์์ง ํ์ธ > Bcrypt๋ฅผ ์ด์ฉํด์ plain password์ ์ํธํ๋ (Hashed) ํจ์ค์๋๊ฐ ๊ฐ์์ง ํ์ธ
3. ๋น๋ฐ๋ฒํธ๊น์ง ๊ฐ๋ค๋ฉด Token ์์ฑ
> ํ ํฐ ์์ฑ์ ์ํด JSONWEBTOKEN ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ค์ด๋ก๋
npm install jsonwebtoken --save
jsonwebtoken
JSON Web Token implementation (symmetric and asymmetric). Latest version: 8.5.1, last published: 3 years ago. Start using jsonwebtoken in your project by running `npm i jsonwebtoken`. There are 19984 other projects in the npm registry using jsonwebtoken.
www.npmjs.com
#ํ ํฐ ์ฟ ํค์ ์ ์ฅํ๊ธฐ
npm cookie-parser --save
*index.js
app.post('/api/users/login', (req, res) =>{
// ์์ฒญ๋ ์ด๋ฉ์ผ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์๋์ง ์ฐพ๊ธฐ
User.findOne({email: req.body.email}, (err, user) => {
if(!user){
return res.json({
loginSuccess: false,
message: "์ ๊ณต๋ ์ด๋ฉ์ผ์ ํด๋นํ๋ ์ ์ ๊ฐ ์์ต๋๋ค."
})
}
// ์์ฒญํ ์ด๋ฉ์ผ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์๋ค๋ฉด ๋น๋ฐ๋ฒํธ๊ฐ ๋ง๋ ๋น๋ฐ๋ฒํธ์ธ์ง ํ์ธ
user.comparePassword(req.body.password, (err, isMatch) => {
if(!isMatch)
return res.json({loginSuccess: false, message: "๋น๋ฐ๋ฒํธ๊ฐ ํ๋ ธ์ต๋๋ค."})
// ๋น๋ฐ๋ฒํธ๊น์ง ๋ง๋ค๋ฉด ํ ํฐ ์์ฑํ๊ธฐ
user.generateToken((err, user) => {
if(err) return res.status(400).send(err);
// ํ ํฐ์ ์ ์ฅํ๊ธฐ ์ด๋? ์ฟ ํค, ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์๋ ์ ์ฅ ๊ฐ๋ฅ > ์ฟ ํค์ ์ ์ฅํ๊ธฐ๋ก ๊ฒฐ์
res.cookie("x_auth", user.token)
.status(200)
.json({loginSuccess: true, userId: user._id})
})
})
})
})
*User.js ์ํธํ๋ ๋น๋ฐ๋ฒํธ ๊ฐ์์ง ๋น๊ต
userSchema.methods.comparePassword = function(plainPassword, cb){
// plainPassword 1234567 ์ํธํ๋ ๋น๋ฐ๋ฒํธ $2b$10$L4PZZ8meTLucmN0ZsxunlOvHap2w7Lxb5Xt0yB5aNYDAiw1pSqQUy
bcrypt.compare(plainPassword, this.password, function(err, isMatch){
if(err) return cb(err);
cb(null, isMatch)
})
}
userSchema.methods.generateToken = function(cb) {
var user = this;
// jsonwebtoken์ ์ด์ฉํด์ token ์์ฑํ๊ฐใ
ฃ
var token = jwt.sign(user._id.toHexString(), 'secretToken')
// user._id + 'secretToken' = token
// ->
// 'secretToken' -> user._id
user.token = token
user.save(function(err, user){
if(err) return cb(err)
cb(null, user)
})
}
#Auth route ๋ง๋ค๊ธฐ
๋ก๊ทธ์ธํ ์ฌ์ฉ์๋ง ๋ค์ด๊ฐ ์ ์๋ ํ์ด์ง / ๊ด๋ฆฌ์๋ง ๋ณผ ์ ์๋ ํ์ด์ง.... ๋ฑ์ ๊ธฐ๋ฅ์ ์ด์ฉํ๊ธฐ ์ํด ๋ง๋ฆ
1. Cookie์์ ์ ์ฅ๋ Token์ Server์์ ๊ฐ์ ธ์์ ๋ณตํธํ Decode
2. ๋ณตํธํ๋ฅผ ํ๋ฉด User ID๊ฐ ๋์ค๋๋ฐ ๊ทธ User ID๋ฅผ ์ด์ฉํด์ ๋ฐ์ดํฐ ๋ฒ ์ด์ค User Collection์์ ์ ์ ๋ฅผ ์ฐพ์ ํ ์ฟ ํค์์ ๋ฐ์์จ token์ด ์ ์ ๋ ๊ฐ๊ณ ์๋์ง ํ์ธ
> ์ฟ ํค๊ฐ ์ผ์นX > Authentication False
> ์ฟ ํค ์ผ์น > Authentication True
*middleware ํด๋ ์ auth.js
const { User } = require('../models/User');
let auth = (req, res, next) => {
// ์ธ์ฆ ์ฒ๋ฆฌ๋ฅผ ํ๋ ๊ณณ
// ํด๋ผ์ด์ธํธ ์ฟ ํค์์ ํ ํฐ ๊ฐ์ ธ์ค๊ธฐ
let token = req.cookies.x_auth;
// ํ ํฐ์ ๋ณตํธํํ ํ ์ ์ ์ฐพ๊ธฐ
User.findByToken(token, (err, user) => {
if(err) throw err;
if(!user) return res.json({isAuth: false, error: true})
// ์ ์ ์์ผ๋ฉด ์ธ์ฆ Okay ์ ์ ์์ผ๋ฉด ์ธ์ฆ No
req.token = token;
req.user = user;
next();
})
}
module.exports = { auth };
*User.js
userSchema.statics.findByToken = function(token, cb){
var user = this;
//user._id + '' = token
// ํ ํฐ์ decode ๋ณตํธํํ๊ธฐ
jwt.verify(token, 'secretToken', function(err, deoded){
// ์ ์ ์์ด๋๋ฅผ ์ด์ฉํด์ ์ ์ ๋ฅผ ์ฐพ์ ๋ค์์
// ํด๋ผ์ด์ธํธ์์ ๊ฐ์ ธ์จ token๊ณผ DB์ ๋ณด๊ด๋ token์ด ์ผ์นํ๋์ง ํ์ธ
user.findOne({"_id":decoded, "token": token}, function(err, user){
if(err) return cb(err);
cb(null, user)
})
})
}
*index.js
app.get('/api/users/auth',auth, (req, res) => {
// ์ฌ๊ธฐ๊น์ง ๋ฏธ๋ค์จ์ด๋ฅผ ํต๊ณผํด์๋ค๋ ์๊ธฐ๋ Authentication์ด True๋ผ๋ ๋ง
res.status(200).json({
_id: req.user._id, // ํด๋ผ์ด์ธํธํํ
์ ๋ฌ
isAdmin: req.user.role ===0 ? false: true, // role์ด 0์ด๋ฉด ์ผ๋ฐ์ ์ , 0์ด ์๋๋ฉด ๊ด๋ฆฌ์
isAuth: true,
email: req.user.email,
name: req.user.name,
lastname: req.user.lastname,
role: req.user.rol,
image: req.user.image
})
})
๐ฃ๋ก๊ทธ์์ ๊ธฐ๋ฅ
๋ก๊ทธ์์ Route ๋ง๋ค๊ธฐ
๋ก๊ทธ์์ํ๋ ค๋ ์ ์ ๋ฅผ ๋ฐ์ดํฐ ๋ฒ ์ด์ค์์ ์ฐพ์์ ๊ทธ ์ ์ ์ ํ ํฐ ์ง์ฐ๊ธฐ
*index.js
app.get('/api/users/logout', auth, (req, res) => {
User.findOneAndUpdate({_id: req.user._id},
{token: ""} // token ์ง์ฐ๊ธฐ
,(err, user) => {
if(err) return res.json({ success: false, err}); // ์๋ฌ๋ ๊ฒฝ์ฐ
return res.status(200).send({ // ์ฑ๊ณตํ ๊ฒฝ์ฐ
success: true
})
})
})
<loginํ์ ๊ฒฝ์ฐ token ์กด์ฌ>
<logoutํ์ ๊ฒฝ์ฐ token ์ง์์ง>