들어가기
1. authenticate 관련해서, backend부터 시작해봅니다.
const express = require('express')
const app = express()
const dotenv = require('dotenv')
///express, dotenv를 import한다.
const databaseConnect = require('./config/db')
const authRouter = require('./routes/authRoute')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
///dataBase, bodyParser, cookieParser를
///불러준다.
dotenv.config({
path: 'backend/config/.env',
})
///server에서 .env파일을 import하는 문법.
///file path를 저정해 준다.
app.use(bodyParser.json())
app.use(cookieParser())
///bodyParser를 넣어서 front에서 오는 data를 받을 수 있게함.
app.use('/api/messenger', authRouter)
///authRouter 사용하긋다.
const PORT = process.env.PORT || 5000
///port저정해 주기
app.get('/', (req, res) => {
res.send('This is backend')
})
///home path접근시 controller
databaseConnect()
///위에서 부른 './db'를 실행한다.
app.listen(PORT, () => {
console.log(`Server is running at ${PORT}`)
})
///서버 시작한다.
const { userRegister, userLogin } = require('../controller/authController')
const router = require('express').Router()
router.post('/user-register', userRegister)
router.post('/user-login', userLogin)
module.exports = router
///router를 불러주는 구 문법을 이해한다.
/// userRegister, userLogin 2개 controller를 만든다.
/// 두 개의 path를 만들어 준다
PORT = 5000
DB_URL=mongodb://localhost:27017/messenger
SECRET_KEY: ASDFEW@234fSDF@
TOKEN_EXP: 7d
COOKIE_EXP=7
///.env 셋팅을 확인한다.
DB만드는 방법, DB connect를 확인한다.
const mongoose = require('mongoose')
const databaseConnect = () => {
mongoose
.connect(process.env.DB_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
///위에 두개는 반사적으로 넣는다.
})
.then(() => {
console.log('Mongo DB connected')
})
.catch((error) => {
console.log(error)
})
///.connect에 성공하면, .then, 실패하면, .catch.
}
module.exports = databaseConnect
const { model, Schema } = require('mongoose')
const registerSchema = new Schema(
{
userName: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
image: { type: String, required: true },
},
{ timestamps: true }
)
module.exports = model('user', registerSchema)
///authModel을 만드는 방법을 확인한다.
const formidable = require('formidable')
///json과 file을 동시에 server에서 받을 경우 사용
///client에서 formData로 보냈을때, 통으로 받음.
const validator = require('validator')
///front에서느 넘어오는 data의 유효성을 확인
const registerModel = require('../models/authModel')
///authModel을 불러줌.
const fs = require('fs')
///file을 다루는 라이브러리
const bcrypt = require('bcrypt')
const jwt = require('jsonwebtoken')
const { options } = require('../routes/authRoute')
///bcrypt, jsonwebtoken을 import 해 준다.
///user Register부분.
module.exports.userRegister = (req, res) => {
const form = formidable()
form.parse(req, async (err, fields, files) => {
const { userName, email, password, confirmPassword } = fields
const { image } = files
const error = []
///form부분을 잘 봐준다.
///formidalble()로 받으면, json, file을 동시에
///server에서 받을 수 있다
///json은 fields로 받고 파일은 files로 서버에서 받는다.
///여기서 error를 담을 error=[]를 만들어 놓는다.
///아래부터 각각의 data가 전송되지 않았다면,
///error=[]에 message를 담아준다.
if (!userName) {
error.push('Please provide your name')
}
if (!email) {
error.push('Please provide your email')
}
if (email && !validator.isEmail(email)) {
error.push('Please provide your valid email')
}
if (!password) {
error.push('Please provide your password')
}
if (!confirmPassword) {
error.push('Please provide your confirmPassword')
}
if (password && confirmPassword && confirmPassword !== password) {
error.push('password is different confirmPassword')
}
if (password && password.length < 6) {
error.push('Please provide password much than 6 chat\r')
}
if (Object.keys(files).length === 0) {
error.push('Please provide user image')
}
///files을 check할 떄, Object.keys(files)로
///files를 확인하는 부분은 잘 확인해 둔다.
if (error.length > 0) {
res.status(400).json({
error: {
errorMessage: error,
},
})
///error에 error가 push된다면,
///error:{errorMessage}에 위에서 만든 error들을
///담아준다.
} else { ///error.length = 0 일 경우~
const getImageName = files.image.originalFilename
const randNumber = Math.floor(Math.random() * 9999)
const newImageName = randNumber + getImageName
files.image.originalFilename = newImageName
///client에서 보내온 fileName을 get해서
///rnadNumber를 만들어서 두 개를 결합해서
///newImageName을 만든 다음, 이름을 교체해 준다.
const newPath =
__dirname +
`../../../frontend/public/image/${files.image.originalFilename}`
///사진이 저장될 path를 만들고 입력될 fileName을
///${}로 만들어 준다.
console.log(newImageName)
try {
const checkUser = await registerModel.findOne({
email: email,
})
///register controller이기 떄문에, email 중복체크함
if (checkUser) {
res.status(404).json({
error: {
errorMessage: ['Your email alreadt exist.'],
},
})
///같은 email이 있으면, error날려줌.
} else {
fs.copyFile(files.image.filepath, newPath, async (error) => {
///fs.copyFile을 이용해서, clinet에서 select한
///filePath, 위에서만든 사진이 저장될 newPath를
///argument로 넣고, callback함수 만듬.
///error가 없을 경우 아래부분 실햄.
if (!error) {
const userCreate = await registerModel.create({
userName,
email,
password: await bcrypt.hash(password, 10),
image: files.image.originalFilename,
})
///DB의 registerModel을 불러서, DB에
///user data를 저장한다.
///password는 hash화 해서 넣어준다.
const token = jwt.sign(
{
id: userCreate._id,
email: userCreate.email,
userName: userCreate.userName,
image: userCreate.image,
registerTime: userCreate.createdAt,
},
///jsonwebtoken을 이용해서 token을 만드는데,
///token에 userInfo를 저장해 놓는다.
process.env.SECRET_KEY,
{ expiresIn: process.env.TOKEN_EXP }
)
///SECRET_KEY와 expiresIn을 설정한다.
const options = {
expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
}
///options로 현재시간 부터 7일 후의 시간을
///만든다.
res.status(201).cookie('authToken', token, options).json({
successMessage: 'Your Register Successful',
token,
})
///201을 날려주고, cookie에 'authToken'으로
///token을 저장시키고,
///client에 token을 return해 준다.
///cookie까지 저장시키는 이유는 추후 알아보자
}
})
}
} catch (error) {
res.status(500).json({
error: {
errorMessage: ['Internal Server error'],
},
})
///error발생시 error=[]에 담아서 errorMessage날려줌.
}
}
})
}
///User Login 부분.
module.exports.userLogin = async (req, res) => {
const error = []
///error를 담을 공간을 만들어 줌.
const { email, password } = req.body
///client부분에서 email, password받아줌.
console.log(email, password)
if (!email) {
error.push('Please provide your email')
}
if (email && !validator.isEmail(email)) {
error.push('Please provide your valid email')
}
if (!password) {
error.push('Please Password provide')
}
if (error.length > 0) {
res.status(400).json({
error: {
errorMessage: error,
},
})
///error발생시, error만들고, error에 담아줌.
} else {
try {
const checkUser = await registerModel.findOne({
email: email,
})
///client에서 받은 email이 DB에 있는지 check함.
if (checkUser) {
const matchPassword = await bcrypt.compare(password, checkUser.password)
///matchPasswordf로 client에서 보내온 password와
///DB의 hash화된 password를 compare해서
///boolean으로 return해 줌.
///true return일때,
if (matchPassword) {
///register와 같이 token을 만들고 return해 준다.
const token = jwt.sign(
{
id: checkUser._id,
email: checkUser.email,
userName: checkUser.userName,
image: checkUser.image,
registerTime: checkUser.createdAt,
},
process.env.SECRET_KEY,
{
expiresIn: process.env.TOKEN_EXP,
}
)
console.log(token)
const options = {
expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
}
res.status(201).cookie('authToken', token, options).json({
successMessage: 'Your login Successful',
token,
})
} else {
res.status(400).json({
error: {
errorMessage: ['Your password not valid'],
},
})
}
} else {
res.status(400).json({
error: {
errorMessage: ['Your email nor found'],
},
})
}
} catch (err) {
res.status(400).json({
error: {
errorMessage: ['Internal server error'],
},
})
}
}
}
///여기까지가 register, login 부분.
formidable부분이 신선하긴 한데,
formidable로 받은 file을 나중에 S3나 cloudflare에
넣을려면, 어떻게 해야 하는지 고민이 필요할듯.
///걍 multer로 받아야 하나 싶기도 함.
이것들은 제가 배우고 있는 복잡한 코드 조각입니다. Vampire Survivors 공유해주셔서 감사합니다