บทความนี้เกี่ยวกับการสร้าง Configuration Middleware สำหรับการใช้งาน Passport Authentication เพื่อให้สามารถง่ายต่อการกำหนดการ Validate JWT Token สำหรับ Route ที่ต้องการ เช่น /user/profile
เนื้อหาจะประกอบไปด้วย 4 ส่วน คือ
- Configuring Passport for Local Authentication
- Register passport with our application
- Configuring Middleware to Validate JWT’s
- 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').secretconst 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
Reference:
(ข้อมูลอาจมีข้อผิดพลาด ถ้าจะเอาบทความนี้ไปอ้างอิงที่อื่นให้ตรวจสอบให้ดีก่อนนะครับ ขอบคุณครับ)
สำหรับวันนี้ ต้องขอลาไปก่อน สวัสดีครับ NottDev :)