DEV Community

Bhurisub Dejpipatpracha
Bhurisub Dejpipatpracha

Posted on

1

Node.js : ระบบ Authentication ที่ทำงานร่วมกับฐานข้อมูล Mongo

จากบทความที่แล้ว ได้แนะนำการเขียนสคริปต์ JavaScript เพื่อทำระบบ Authentication แบบพื้นฐาน ด้วยมอดูล Passport สำหรับในบทความนี้จะขอแนะนำการเขียนสคิปต์ทำระบบ Authentication ทำงานร่วมกับฐานข้อมูล Mongo โดยเราจะเก็บข้อมูลสมาชิกไว้ใน Collection users

ซึ่งขอยกตัวอย่างข้อมูล db.users.find()

{ 
   _id:OjectId("5daa74efb50ece2f98643d35"),
   username:"anakin",
   password:"1234",
   fname:"Anakin",
   lname:"Skywalker"
}
{ 
   _id:OjectId("5daa748b1a5fc22f98b6db32"),
   username:"bhurisub",
   password:"1234",
   fname:"Bhurisub",
   lname:"Dejpipatpracha"
}

เราจะนำเอาสคริปต์ในบทความที่ผ่านมาปรับปรุง โดยเริ่มจากติดตั้งมอดูลเพิ่มเติม
npm i mongodb

สคริปต์ views/home.ejs ปรับปรุงหน้าหลักสมาชิก

...
...
      <div class="container">
          <div class="row">
            <h1>:: Home ::</h1>
          </div>
          <div class="row">
             Login Ok.<br/><br/> 
             _id = <%=_id%> <br/>
             Username = <%=username%> <br/>
             Name = <%=fname%> <%=lname%> <br/><br/>
          </div>
          <div class="row">
            <a href='./logout'>Logout</a>
          </div>
      </div>
...
...

สร้างสคริปต์ config.js สำหรับติดต่อฐานข้อมูล Mongo

const MongoClient = require('mongodb').MongoClient  

const url = 'mongodb://localhost:27017' 
const dbName = 'webphuket' 

module.exports = new Promise((resolve, reject)=>{
    MongoClient.connect(url, { useNewUrlParser: true,useUnifiedTopology: true },(err, client) => {
        if (err) throw err
        const mongo = client.db(dbName)
        console.log("Connected successfully to server")
        resolve(mongo)
    })
})

สคริปต์ index.js (ปรับปรุง)

const express = require('express')
const app = express()
app.use(express.static(__dirname + '/public'))
app.set('view engine', 'ejs')

const MongoObjectID = require('mongodb').ObjectID
const mongo = require('./config')

const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy

const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(cookieParser())

const session = require('express-session')
app.use(session({ secret: 'I am Anakin.', resave: true, saveUninitialized: true }))
app.use(passport.initialize())
app.use(passport.session())

passport.use(new LocalStrategy((username, password, done) => {
    mongo.then((db) => {
        query = { username : username }
        db.collection('users').findOne(query,(err, user) => {
            if (err) return done(err)

            if (!user) {
                console.log('Incorrect username.')
                return done(null, false, { message: 'Incorrect username.' })
            } else if (user.password == password ) {
                console.log('Correct password.')
                return done(null, user)
            } else {
                console.log('Incorrect password.')
                return done(null, false, { message: 'Incorrect password.' })
            }
        })
    })
}))

passport.serializeUser((user, done) => {
    console.log('SerializeUser')
    done(null, user._id) 
})

passport.deserializeUser((id, done) => {
    mongo.then((db) => {
        query = { _id : new MongoObjectID.ObjectID(id) }
        db.collection('users').findOne(query,(err, user) => {
            if (err) return done(err)

            console.log('DeserializeUser')
            done(null, user) 
        })
    })
})

app.get('/', (req, res) =>  {
    res.render('login')
})

app.get('/login', (req, res) =>  {
    res.render('login')
})

app.post('/login', passport.authenticate('local', { 
    successRedirect: '/home',
    failureRedirect: '/' 
}))

function isLoggedIn(req, res, next) {
    if (req.isAuthenticated()) {
        return next()
    } else {
        res.redirect('/')
    }
}

app.get('/home',isLoggedIn,(req,res) => {
    res.render('home',req.user)
})

app.get('/logout',(req,res) => {
    req.logout()
    res.redirect('/')
})

app.listen(3000, () => {
    console.log('Server Started on localhost:3000...')
})

เรียกใช้ ObjectID เก็บไว้ในตัวแปร MongoObjectID และเรียกใช้การติดต่อฐานข้อมูล Mongo เก็บไว้ในตัวแปร mongo

const MongoObjectID = require('mongodb').ObjectID
const mongo = require('./config')

กำหนดการตรวจสอบสมาชิกในฐานข้อมูล Mongo เรียกแสดงข้อมูลใน collection ชื่อ users ที่ username ตามที่ผู้ใช้ป้อนมาจากฟอร์ม หากค้นหาข้อมูลได้แล้วก็จะเก็บไว้ใน user

จากนั้นตรวจสอบ user ว่ามีข้อมูลหรือไม่ หากไม่มีแสดงว่าผู้ใช้ป้อน Username ที่ไม่มีอยู่ใน Collection
และหากรหัสผ่านที่ดึงมาจาก collection ตรงกับรหัสผ่านที่ผู้ใช้ป้อน และหากไม่ถูกตอ้งก็แสดงว่า รหัสผ่านของ Username ดังกล่าวไม่ตรงกับที่อยู่ในฐานข้อมูล

passport.use(new LocalStrategy((username, password, done) => {
    mongo.then((db) => {
        query = { username : username }
        db.collection('users').findOne(query,(err, user) => {
            if (err) return done(err)

            if (!user) {
                console.log('Incorrect username.')
                return done(null, false, { message: 'Incorrect username.' })
            } else if (user.password == password ) {
                console.log('Incorrect password.')
                return done(null, user)
            } else {
                console.log('Incorrect password.')
                return done(null, false, { message: 'Incorrect password.' })
            }
        })
    })
}))

สำหรับในการเก็บข้อมูลใน Session เราจะเก็บเฉพาะ _id ของ Username เท่านั้น

passport.serializeUser((user, done) => {
    console.log('SerializeUser')
    done(null, user._id) 
})

หลังจากนั้นนำ id ที่เก็บไว้ Seesion ไปใช้อ้างอิงเพื่อดึงข้อมูลสมาชิกใน collection users เก็บไว้ในตัวแปร user

passport.deserializeUser((id, done) => {
    mongo.then((db) => {
        query = { _id : new MongoObjectID.ObjectID(id) }
        db.collection('users').findOne(query,(err, user) => {
            if (err) return done(err)

            console.log('DeserializeUser')
            done(null, user) 
        })
    })
})

ขอจบบทความนี้เพียงเท่านี้ ครับ ;)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

nextjs tutorial video

Youtube Tutorial Series 📺

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series