ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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})
            }
        },

    다시한번 postman으로 register하면 데이터가 잘 저장된 것을확인할 수 있다. 

    이미데이터 베이스에 저장이 되어있기 때문에 이제 같은 이름으로 등록하려고 해도 안된다. 

     

     

    이제 로그인 부분도 만들어주자. 

    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})
            }
        }
    }

     

     

Designed by Tistory.