-
Social Media 만들기 - 2) Authentification 기능 만들기NODE.JS 2021. 6. 16. 12:08
우선 npm run dev해서 백엔드를 실행해주고,
models에 userModel.js파일을 만들어준다.
const mongoose = require('mongoose') const userSchema = new mongoose.Schema({ fullname:{ type:String, required:true, trim:true, maxlength:25 }, username:{ type:String, required:true, trim:true, maxlength:25, unique:true }, email:{ type:String, required:true, trim:true, unique:true }, password:{ type:String, required:true }, avatar:{ type:String, default:'https://image.flaticon.com/icons/png/512/1077/1077063.png' }, role:{ type:String, default:user, }, gender:{ type:String, default:'male' }, mobile:{ type:String, default:'' }, address:{ type:String, default:'' }, story:{ type:String, default:'', maxlength:200 }, website:{ type:String, default:'' }, followers:[ { type : mongoose.Types.ObjectId, ref:'user' } ], following:[ { type : mongoose.Types.ObjectId, ref:'user' } ], }, {timestamps:true}) module.exports = mongoose.model('user', userSchema)
이후 controllers에 authCtrl.js파일을 만들어준다.
const Users = require('../models/userModel') const bcrypt = require('bcrypt') const jwt = require('jsonwebtoken') const authCtrl={ register : async(req, res)=>{ try{ } catch(err){ return res.status(500).json({msg:err.message}) } }, login : async(req, res)=>{ try{ const {fullname, username, email, password, gender} = req.body } catch(err){ return res.status(500).json({msg:err.message}) } }, logout : async(req, res)=>{ try{ } catch(err){ return res.status(500).json({msg:err.message}) } }, generateAccessToken : async(req, res)=>{ try{ } catch(err){ return res.status(500).json({msg:err.message}) } } } module.exports = authCtrl
routes폴더에 authRouter.js파일을 만들어준다.
const router = require('express').Router() const authCtrl = require('../controllers/authCtrl') router.post('/register', authCtrl.register) router.post('/login', authCtrl.login) router.post('/logout', authCtrl.logout) router.post('/refresh_token', authCtrl.generateAccessToken) module.exports = router
server.js로 가서 작성해준다.
require('dotenv').config() const express = require('express') const mongoose = require('mongoose') const cors = require('cors') const cookieParser = require('cookie-parser') const app = express() app.use(express.json()) app.use(cors()) app.use(cookieParser()) // Routes app.use('/api', require('./routes/authRouter')) const URI = process.env.MONGODB_URL mongoose.connect(URI,{ useCreateIndex:true, useFindAndModify:false, useNewUrlParser:true, useUnifiedTopology:true }, err=> { if(err) throw err; console.log('Connected to mongodb') }) const port = process.env.POR || 5000 app.listen(port, ()=>{ console.log('Server is running on port', port) })
다시 컨트롤러로 가서 다음과 같이 작성해서 작동하는지 확인하자
register : async(req, res)=>{ try{ const {fullname, username, email, password, gender} = req.body console.log(req.body) res.json({msg:'Registed!'}) } catch(err){ return res.status(500).json({msg:err.message}) } },
포스트맨에서 확인해보자.
데이터도 잘 뜬다.
const Users = require('../models/userModel') const bcrypt = require('bcrypt') const jwt = require('jsonwebtoken') const authCtrl={ register : async(req, res)=>{ try{ const {fullname, username, email, password, gender} = req.body let newUserName = username.toLowerCase().replace(/ /g, '') const user_name = await Users.findOne({username:newUserName}) if(user_name)return res.status(400).json({msg:"This user name already exists."}) const user_email = await Users.findOne({email}) if(user_email)return res.status(400).json({msg:"This email already exists."}) if(password.length<6) return res.status(400).json({msg:"Password must be at least 6 characters"}) const passwordHash = await bcrypt.hash(password, 12) const newUser = new Users({ fullname, username:newUserName, email, password:passwordHash, gender }) console.log(newUser) // const access_token = createAccessToken({id:newUser._id}) // const refresh_token = createRefreshToken({id:newUser._id}) res.json({ msg:'Register Success!' }) } catch(err){ return res.status(500).json({msg:err.message}) } }, login : async(req, res)=>{ try{ } catch(err){ return res.status(500).json({msg:err.message}) } }, logout : async(req, res)=>{ try{ } catch(err){ return res.status(500).json({msg:err.message}) } }, generateAccessToken : async(req, res)=>{ try{ } catch(err){ return res.status(500).json({msg:err.message}) } } } module.exports = authCtrl
작동하는지 확인하자
토큰생성하는기능을 만들고 제대로 잘 작동하는지 확인하자.
const Users = require('../models/userModel') const bcrypt = require('bcrypt') const jwt = require('jsonwebtoken') const authCtrl={ register : async(req, res)=>{ try{ const {fullname, username, email, password, gender} = req.body let newUserName = username.toLowerCase().replace(/ /g, '') const user_name = await Users.findOne({username:newUserName}) if(user_name)return res.status(400).json({msg:"This user name already exists."}) const user_email = await Users.findOne({email}) if(user_email)return res.status(400).json({msg:"This email already exists."}) if(password.length<6) return res.status(400).json({msg:"Password must be at least 6 characters"}) const passwordHash = await bcrypt.hash(password, 12) const newUser = new Users({ fullname, username:newUserName, email, password:passwordHash, gender }) const access_token = createAccessToken({id:newUser._id}) const refresh_token = createRefreshToken({id:newUser._id}) console.log({access_token, refresh_token}) res.json({ msg:'Register Success!' }) } catch(err){ return res.status(500).json({msg:err.message}) } }, login : async(req, res)=>{ try{ } catch(err){ return res.status(500).json({msg:err.message}) } }, logout : async(req, res)=>{ try{ } catch(err){ return res.status(500).json({msg:err.message}) } }, generateAccessToken : async(req, res)=>{ try{ } catch(err){ return res.status(500).json({msg:err.message}) } } } const createAccessToken = (payload) =>{ return jwt.sign(payload,process.env.ACCESS_TOKEN_SECRET, {expiresIn:'1d'} ) } const createRefreshToken= (payload) =>{ return jwt.sign(payload,process.env.REFRESH_TOKEN_SECRET, {expiresIn:'30d'} ) } module.exports = authCtrl
.env 에 다음과 같이 추가해준다.
ACCESS_TOKEN_SECRET = myaccesstokensecret REFRESH_TOKEN_SECRET = myrefreshtokensecret
토큰이 잘 생성되었다.
다음과 같이 바꿔보자.
register : async(req, res)=>{ try{ const access_token = createAccessToken({id:newUser._id}) const refresh_token = createRefreshToken({id:newUser._id}) res.cookie('refreshtoken', refresh_token, { httpOnly:true, path:'/api/refresh_token', maxAge:30*7*24*60*60*1000 //30days }) res.json({ msg:'Register Success!' , access_token, user:{ ...newUser._doc, password:'' } }) } catch(err){ return res.status(500).json({msg:err.message}) } },
register할때마다 refreshtoken이 잘 생성된다.
이제 mongodb에도 저장해보자.
const Users = require('../models/userModel') const bcrypt = require('bcrypt') const jwt = require('jsonwebtoken') const authCtrl={ register : async(req, res)=>{ try{ const {fullname, username, email, password, gender} = req.body let newUserName = username.toLowerCase().replace(/ /g, '') const user_name = await Users.findOne({username:newUserName}) if(user_name)return res.status(400).json({msg:"This user name already exists."}) const user_email = await Users.findOne({email}) if(user_email)return res.status(400).json({msg:"This email already exists."}) if(password.length<6) return res.status(400).json({msg:"Password must be at least 6 characters"}) const passwordHash = await bcrypt.hash(password, 12) const newUser = new Users({ fullname, username:newUserName, email, password:passwordHash, gender }) const access_token = createAccessToken({id:newUser._id}) const refresh_token = createRefreshToken({id:newUser._id}) res.cookie('refreshtoken', refresh_token, { httpOnly:true, path:'/api/refresh_token', maxAge:30*7*24*60*60*1000//30days }) await newUser.save();//mongodb에 데이터 저장 res.json({ msg:'Register Success!' , access_token, user:{ ...newUser._doc, password:'' } }) } catch(err){ return res.status(500).json({msg:err.message}) } },
이미데이터 베이스에 저장이 되어있기 때문에 이제 같은 이름으로 등록하려고 해도 안된다.
이제 로그인 부분도 만들어주자.
login : async(req, res)=>{ try{ const {email, password} =req.body const user = await Users.findOne({email}) .populate("followers follwing", "-password") if(!user) return res.status(400).json({msg: "Invalid Email"}) const isMatch = await bcrypt.compare(password, user.password) if(!isMatch) return res.status(400).json({msg: "Invalid Password."}) const access_token = createAccessToken({id:user._id}) const refresh_token = createRefreshToken({id:user._id}) res.cookie('refreshtoken', refresh_token, { httpOnly:true, path:'/api/refresh_token', maxAge:30*7*24*60*60*1000//30days }) res.json({ msg:'Login Success!' , access_token, user:{ ...user._doc, password:'' } }) } catch(err){ return res.status(500).json({msg:err.message}) } },
이제 로그아웃도 구현하자.
logout : async(req, res)=>{ try{ res.clearCookie('refreshtoken', {path:'/api/refresh_token'}) return res.json({msg:"Logged Out"}) } catch(err){ return res.status(500).json({msg:err.message}) } }, generateAccessToken : async(req, res)=>{ try{ } catch(err){ return res.status(500).json({msg:err.message}) } }
로그아웃하면 쿠키도 사라진다.
이제 generateAccessToken을 보자.
generateAccessToken : async(req, res)=>{ try{ const rf_token = req.cookies.refreshtoken res.json({rf_token}) } catch(err){ return res.status(500).json({msg:err.message}) } }
다시 로그인 하고 보면, 잘 나온다.
generateAccessToken : async(req, res)=>{ try{ const rf_token = req.cookies.refreshtoken if(!rf_token)return res.status(400).json({msg:"Login first."}) jwt.verify(rf_token, process.env.REFRESH_TOKEN_SECRET, async(err, result)=>{ if(err) return res.status(400).json({msg:"Login first."}) console.log(result) const user = await Users.findById(result.id).select("-password") .populate('followers following', '-password') if(!user) return res.status(400).json({msg:"User Not Found."}) const access_token = createAccessToken({id:result.id}) res.json({ access_token, user }) }) } catch(err){ return res.status(500).json({msg:err.message}) } } }
'NODE.JS' 카테고리의 다른 글
Social Media 만들기 - 4) Register 기능 만들기 (0) 2021.07.06 Social Media 만들기 - 3) Redux , RefreshToken (Login 기능 만들기) (0) 2021.07.05 아마존 E-commerce 클론 -33) 채팅 기능 만들기(socket io) (0) 2021.05.30 아마존 E-commerce 클론 -32) 차트 스크린 만들기 (0) 2021.05.30 아마존 E-commerce 클론 -31) Order Receipt 이메일로 보내기 (0) 2021.05.30