สร้าง Config Middleware for Passport Authentication

NottDev
2 min readDec 6, 2019

--

บทความนี้เกี่ยวกับการสร้าง Configuration Middleware สำหรับการใช้งาน Passport Authentication เพื่อให้สามารถง่ายต่อการกำหนดการ Validate JWT Token สำหรับ Route ที่ต้องการ เช่น /user/profile

เนื้อหาจะประกอบไปด้วย 4 ส่วน คือ

  1. Configuring Passport for Local Authentication
  2. Register passport with our application
  3. Configuring Middleware to Validate JWT’s
  4. Configuring Validate JWT Token

Project Directory Structure

passport-jwt/
+-- configs
¦ +-- auth.js
¦ +-- passport.js
+-- routes
¦ +-- auth.js
¦ +-- users.js
+-- app.js
+-- package.json

Configuring Passport for Local Authentication

ในตัวอย่างนี้เราใช้การยืนยันตัวตนแบบ passport-local strategy นั้นคือ ตรวจสอบด้วย username/password จากการ login ของผู้ใช้ที่ส่งมาทาง request body โดยสร้างไฟล์ configs/passport.js โค้ดตามด้านล่าง

// configs/passport.jsconst passport = require('passport')
LocalStrategy = require('passport-local').Strategy,
mongoose = require('mongoose'),
User = mongoose.model('User')
passport.use(new LocalStrategy({
usernameField: 'user[email]',
passwordField: 'user[password]'
}, (email, password, done) => {
User.findOne({email: email}).then(function(user){
if(!user || !user.validPassword(password)){
return done(null, false, {errors: {'email or password': 'is invalid'}})
}
return done(null, user)
}).catch(done)
}))

สำหรับการยืนยันแบบ LocalStrategy โดยปกติจะตรวจสอบจากฟิลด์ username และ password ที่ Client ส่งมาใน Request body หากเรามีการส่งในรูปแบบอื่น เช่น

{
"user": {
"email": "nottdev@example.com".
"password": "my-password"
}
}

เราต้องทำการ config เพิ่มเติมใน passport-local strategy ว่าต้องการ Map กับ field อะไร

{
usernameField: 'user[email]',
passwordField: 'user[password]'
}

จากโค้ด config ด้านบนคือ บอกว่า username field รับค่าจาก user[email] และ password field รับค่าจาก user[email]

Register passport with our application

require ไฟล์ /configs/password.js ในไฟล์ /app.js เพื่อเรียกใช้งาน Password Authentication

require('./models/User'); + require('./config/passport');  app.use(require('./routes'));

Configuring Middleware to Validate JWT’s

สร้างไฟล์ /routes/auth.js สำหรับการทำ Middleware ตรวจสอบ JWT Token โดยเราจะใช้ express-jwt ซึ่งเป็น module ที่ใช้ตรวจสอบการยืนยันตัวตนจากขอร้องจาก client ด้วย JWT Token ซึ่งหาก token ที่ส่งมาถูกต้องก็จะเซ็ต req.user เท่ากับ user object แต่ถ้าหาก token ไม่ถูกต้องจะตอบกลับด้วย 401 Unauthorize พร้อม error message ซึ่งเราใช้สำหรับ protect API endpoints ที่เราต้องการนั้นเอง

// configs/auth.jsconst jwt = require('express-jwt'),
secret = require('../configs').secret
const getTokenFromHeader = req => {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Token' || req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1]
}
return null
}
const auth = {
required: jwt({
secret: secret,
userProperty: 'payload',
getToken: getTokenFromHeader
}),
optional: jwt({
secret: secret,
userProperty: 'payload',
credentialsRequired: false,
getToken: getTokenFromHeader
})
}
module.exports = auth

getTokenFromHeader() คือฟังก์ชันช่วยสำหรับ extract JWT จาก header ซึ่งรองรับทั้งการระบุเป็น Token <token> และ Bearer <token>

  • secret คือคีร์ลับสำหรับใช้ถอดรหัสข้อมูล โดยต้องตรงกับที่ใช้เข้ารหัส
  • userProperty คือกำหนดชื่อตัวแปรสำหรับเก็บค่า JWT Payloads (default req.user)
  • credentialsRequired คือกำหนดว่าต้องการยืนยันตัวตนหรือไม่
  • getToken คือค่า JWT Token

Configuring Validate JWT Token

เมื่อทุกอย่างพร้อมแล้ว ขั้นตอนสุดท้ายก็คือ การ config กำหนดใช้ middleware validate JWT Token กับ route ที่ต้องการ

// route/user.jsconst router = require('express').Router(),
auth = require('../configs/auth')
/* GET users listing. */
router.get('/', auth.required, (req, res, next) => {
res.send('respond with a resource');
});
/* GET user profile. */
router.get('/profile', auth.required, (req, res, next) => {
res.send(req.user);
});
module.exports = router;

สำหรับ routes/articles.js

// routes/articles.jsconst router = require('express').Router(),
auth = require('../configs/auth')
/* GET articles listing. */
router.get('/', auth.optional, (req, res, next) => {
res.send('respond with a resource');
});
module.exports = router;

สำหรับความแตกต่างของแต่ละ configs คือ

  • auth.required มีการยืนยันตัวตน และเซ็ต req.user เท่ากับ user object
  • auth.optional ไม่มีการยืนยันตัวตน แต่ถ้ามี JWT Token ถูกต้อง ก็เซ็ต req.user

Source Code Github

Reference:

(ข้อมูลอาจมีข้อผิดพลาด ถ้าจะเอาบทความนี้ไปอ้างอิงที่อื่นให้ตรวจสอบให้ดีก่อนนะครับ ขอบคุณครับ)

สำหรับวันนี้ ต้องขอลาไปก่อน สวัสดีครับ NottDev :)

--

--

NottDev
NottDev

Written by NottDev

Your only limit is your mind.

No responses yet