๐ฉ๐ป ๋ฐฑ์๋(Back-End)/Node js
[ํ์๊ฐ์ , ๋ก๊ทธ์ธ API ์ธ์ฆํ๊ธฐ] Node JS using JWT & MongoDB
์ง์ง์ํ์นด
2023. 2. 25. 23:43
728x90
๋ฐ์ํ
https://www.youtube.com/watch?v=ZEg03f1o_vQ&list=LL&index=6
์~ ๋ ์ด๋ ต๋ค
โญ ํ์ผ ๊ตฌ์กฐ
โญ ์ธ๋ถ ํ์ผ
๐ปconfig/db.config.js
module.exports = {
db : "mongodb+srv://~~~~~~~"
}
๐ปcontrollers/user.controller.js
'use strict';
// ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํํด์ ์ ์ฅํ๊ธฐ
const bcryptjs = require("bcryptjs");
const userSesrvice = require("../services/user.services");
exports.register = (req, res, next) => {
const {password} = req.body;
// ์ํธ + ๋น๋ฐ๋ฒํธ๋ฅผ ํด์๋ก ์ํธํ
const salt = bcryptjs.genSaltSync(10);
// ๋น๋๊ธฐ ๋ฐฉ์ ํ๋ผ๋ฏธํฐ, ์ํธํ์ ์ฌ์ฉ๋๋ Salt
req.body.password = bcryptjs.hashSync(password, salt);
userSesrvice.register(req.body, (error, result) => {
if(error) {
return next(error);
}
return res.status(200).send({
message : "Success",
data : result,
});
});
};
exports.login = (req, res, next) => {
const { username, password } = req.body;
userSesrvice.login({ username, password }, (error, result) => {
if(error) {
return next(error);
}
return res.status(200).send({
message : "Success",
data : result,
});
})
}
exports.userProfile = (req, res, next) => {
if (req.user) {
res.send(req.user);
next();
} else {
return res.status(401).json({ message: 'Invalid token' });
}
};
๐ปmiddlewares/auth.js
'use strict';
const dotenv = require('dotenv');
// JWT(JSON Web Token - JSON ์น ํ ํฐ)์ ๋ ๊ฐ์ฒด ์ฌ์ด์์ ์์ ํ๊ฒ ํด๋ ์์ ์ ๋ฌ(ํํ)
// 1) HEADER(ํค๋) typ : ํ ํฐ์ ํ์
์ ์ง์ (JWT), alg : ํด์ฑ ์๊ณ ๋ฆฌ์ฆ์ ์ง์
// 2) PAYLOAD(๋ด์ฉ) - ์ฌ์ฉ๋๋ ์ ๋ณด์ ํ ์กฐ๊ฐ์ ํด๋ ์(claim)
// 3) VERIFY SIGNATURE(์๋ช
) : header + payload ์ ๋ณด๋ฅผ ๋น๋ฐํค๋ก ํด์ฌ๋ฅผ ํ์ฌ ์์ฑ!
const jwt = require("jsonwebtoken");
dotenv.config();
// ๋ก๊ทธ์ธ ์ ํด๋น id, pw์ ์ผ์นํ๋ ์์ฒญ์ด ๋ค์ด์ค๋ฉด access token๊ณผ refresh token์ ๋ฐ๊ธ
// ๋ฐ๊ธ๋ token์ ํด๋ผ์ด์ธํธ์์ ์์ฒญ์ ๋ณด๋ผ ๋๋ง๋ค
// headers์ authorization: 'bearer ' + accessToken ๋ฐฉ์์ผ๋ก ๋๊ฒจ๋ฐ์ ํด๋น ์์ฒญ์ token์ด ์ ํจํ์ง ๊ฒ์ฌ
function authenticateToken(req, res, next) {
// access token์ ์ ํจ์ฑ ๊ฒ์ฌ
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[0];
if (token == null) {
console.log("์๋ชป๋ token์ด๋ค!!!")
return res.sendStatus(401);
}
// verify๋ฅผ ํตํด ๊ฐ decode
jwt.verify(token, "Snippet_SecretKEY", (err, user) => {
if(err) return res.sendStatus(403);
req.user = user;
next();
});
};
function generateAccessToken(username) {
// sign ๋ฉ์๋๋ฅผ ํตํด access token ๋ฐ๊ธ (process.env.ACCESS_TOKEN_SECRET)
return jwt.sign({data : username},"Snippet_SecretKEY", {
expiresIn : "1h"
});
};
module.exports = {
authenticateToken,
generateAccessToken,
};
๐ปmiddlewares/errors.js
function errorHandler(err, req, res, next) {
if(typeof err === "string") {
// 400(์๋ชป๋ ์์ฒญ): ์๋ฒ๊ฐ ์์ฒญ์ ๊ตฌ๋ฌธ์ ์ธ์ํ์ง ๋ชปํ๋ค
return res.status(400).json({message : err});
}
if(typeof err === "ValidationError") {
return res.status(400).json({message : err.message});
}
if(typeof err === "UnauthorizedError") {
// 401(๊ถํ ์์): ์ด ์์ฒญ์ ์ธ์ฆ์ด ํ์
return res.status(401).json({message : err.message});
}
// 500 (๋ด๋ถ ์๋ฒ ์ค๋ฅ): ์๋ฒ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ฌ ์์ฒญ์ ์ํํ ์ ์๋ค
return res.status(500).json({message : err.message});
};
module.exports = {
errorHandler,
};
๐ปmodels/user.mode.js
const mongoose = require("mongoose");
const {Schema} = mongoose;
// Mongoose ์คํค๋ง ๋ด์ ๊ณ ์ ํ ํ๋์ ๋ํ ์ฌ์ ์ ์ฅ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ถ๊ฐํ๋ ํ๋ฌ๊ทธ์ธ
const uniqueValidator = require("mongoose-unique-validator");
const userSchema = new Schema ({
username : {
type : String,
required : true
},
email : {
type : String,
required : true,
unique : true
},
password : {
type : String,
required : true
},
date : {
type : Date,
default : Date.now()
}
});
userSchema.set("toJSON", {
transform : (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString();
// _id, _v, password ์ ์ญ ์คํค๋ง ์ค์ ์ ๋ฑ๋กํ์ฌ ์ญ์
delete returnedObject._id;
delete returnedObject.__v;
delete returnedObject.password;
},
});
// unique์ ์กด์ฌ ์ ๋ฌด๋ ํ์
userSchema.plugin(uniqueValidator, { message : "Email ์ด๋ฏธ ์ฌ์ฉ ์ค"});
// schema๋ฅผ ์ฌ์ฉํ๋ model
const User = mongoose.model("user", userSchema);
module.exports = User;
๐ปmodels/user.mode.js
'use strict';
const userController = require("../controllers/user.controller");
const express = require("express");
const router = express.Router();
router.post("/register", userController.register);
router.post("/login", userController.login);
router.post("/userProfile", userController.userProfile);
module.exports = router;
๐ปservices/user.services.js
'use strict';
const User = require("../models/user.model");
const bcrypt = require("bcryptjs");
const auth = require("../middlewares/auth.js")
async function login({ username, password }, callback) {
const user = await User.findOne({ username });
if (user != null) {
// client๊ฐ ์
๋ ฅํ password์ user.passward์ ์ผ์นํ์ง ํ์ธ
if (bcrypt.compareSync(password, user.password)) {
// accessToken ์์ฑ๊ธฐ (middleware์์ ๋ฐํ)
const token = auth.generateAccessToken(username);
return callback(null, {...user.toJSON(), token});
}
else {
return callback({
message : "์ผ์นํ์ง ์์ ์์ด๋์ ๋น๋ฐ๋ฒํธ์
๋๋ค.",
});
}
} else {
return callback({
message : "์ผ์นํ์ง ์์ ์์ด๋์ ๋น๋ฐ๋ฒํธ์
๋๋ค.",
});
}
}
async function register(params, callback) {
const user = new User(params);
if(params.username === undefined) {
return callback({message : "์์ด๋ ์
๋ ฅํด์ฃผ์ธ์"});
}
user.save()
.then((response) => {
return callback(null, response);
})
.catch((error) => {
return callback(error);
});
}
module.exports = {
login,
register,
};
๐ปapp.js
'use strict';
const express = require("express");
const mongoose = require("mongoose");
const dbConfig = require("./config/db.config");
const dotenv = require('dotenv');
dotenv.config();
const auth = require("./middlewares/auth");
const errors = require("./middlewares/errors");
const {unless} = require("express-unless");
const app = express();
// ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์์ฒญ
mongoose.Promise = global.Promise;
mongoose.connect(dbConfig.db, {
// useNewUrlParser, useUnifiedTopology ์ต์
์ ์๋ฒ ์คํ ์ ๋ฐ์๋๋ ์ค๋ฅ๋ฅผ ์ ๊ฑฐ
useNewUrlParser : true,
useUnifiedTopology : true
}).then(
() => {
console.log("db ์ฐ๊ฒฐ ์ฑ๊ณต")
},
(error) => {
console.log("db ์ฐ๊ฒฐ ์๋จ : " + error);
}
);
// authenticateToken : ๋ฏธ๋ค์จ์ด - ๋ณดํธ๋ ๊ฒฝ๋ก์ ์ก์ธ์คํ๊ธฐ ์ ์ ํ ํฐ์ ์ธ์ฆ
auth.authenticateToken.unless = unless
console.log(auth.authenticateToken.unless);
app.use(auth.authenticateToken.unless({
path: [
{ url: '/users/login', methods: ['POST']},
{ url: '/users/register', methods: ['POST']}
]
}));
// ํด๋ผ์ด์ธํธ๋ก ๋ถํฐ ๋ฐ์ http ์์ฒญ ๋ฉ์์ง ํ์์์ body๋ฐ์ดํฐ๋ฅผ ํด์
app.use(express.json());
app.use("/users", require("./routes/user.routes"));
app.use(errors.errorHandler);
app.listen(process.env.PORT || 4000, function() {
console.log("๐ ์์ํด๋ณผ๊น!")
})
๐ปpackage.json
{
"name": "mangement",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.3",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"express-unless": "^2.1.3",
"jsonwebtoken": "^9.0.0",
"mongoose": "^6.9.2",
"mongoose-unique-validator": "^3.1.0"
}
}
โญ ๊ฒฐ๊ณผ
๐ปregister ํ์๊ฐ์ ํ๊ธฐ
๐ปlogin ๋ก๊ทธ์ธ ํ๊ธฐ
๐ปuser ํ์ธํ๊ธฐ
: login ํ์ ๋ token์ authorization์ value ๊ฐ์ ๋ฃ์ด์ ํ์ธํ๊ธฐ!!!
728x90
๋ฐ์ํ