Node.js : ระบบ Authentication ที่ทำงานร่วมกับฐานข้อมูล Mongo 
Tags: node, javascript, passport, mongodb
Published: 2019-10-20 08:49:56

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

ซึ่งขอยกตัวอย่างข้อมูล db.users.find()
```javascript
{ 
   _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 ปรับปรุงหน้าหลักสมาชิก
```html
...
...
      <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
```javascript
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 (ปรับปรุง)
```javascript
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
```javascript
const MongoObjectID = require('mongodb').ObjectID
const mongo = require('./config')
```

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

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

```javascript
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 เท่านั้น
```javascript
passport.serializeUser((user, done) => {
    console.log('SerializeUser')
    done(null, user._id) 
})
```

หลังจากนั้นนำ id ที่เก็บไว้ Seesion ไปใช้อ้างอิงเพื่อดึงข้อมูลสมาชิกใน collection users เก็บไว้ในตัวแปร user
```javascript
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) 
        })
    })
})
```

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