ใช้งานการตรวจสอบสิทธิ์ JWT ใน API ของ Node.js อย่างมืออาชีพ

การปรับปรุงครั้งล่าสุด: 02/11/2026
  • JWT ช่วยให้การตรวจสอบสิทธิ์แบบไร้สถานะและปรับขนาดได้สำหรับ API ของ Node.js ผสานรวมเข้ากับเส้นทางและมิดเดิลแวร์ของ Express ได้อย่างราบรื่น
  • การผสานรวม Express, Mongoose, jsonwebtoken, bcrypt, Joi และ dotenv เข้าด้วยกัน จะสร้างรากฐานที่ปลอดภัยและยืดหยุ่นสำหรับการตรวจสอบสิทธิ์ผู้ใช้
  • การตรวจสอบ JWT แบบ JWKS ช่วยให้ API ของ Node.js สามารถเชื่อถือเซิร์ฟเวอร์การอนุญาตภายนอก และบังคับใช้ขอบเขตและข้อมูลอ้างอิงได้อย่างชัดเจน
  • การตรวจสอบความถูกต้องอย่างละเอียด การจัดการข้อผิดพลาดที่ชัดเจน และการทดสอบที่เป็นระบบ เป็นสิ่งสำคัญในการรักษาเสถียรภาพของเอนด์พอยต์ที่ได้รับการปกป้องด้วย JWT

การตรวจสอบสิทธิ์ API JWT ของ Node.js

หากคุณกำลังสร้าง API ด้วย Node.js การเพิ่มระบบตรวจสอบสิทธิ์ที่ถูกต้องด้วย JWT อาจดูเหมือนเป็นเรื่องน่ากลัวในตอนแรก แต่จริงๆ แล้วมันไม่จำเป็นต้องเป็นเช่นนั้น ด้วยไลบรารีที่คัดสรรมาอย่างดี โครงสร้างที่ชัดเจน และแนวปฏิบัติที่ดีเกี่ยวกับการตรวจสอบความถูกต้องและความปลอดภัย คุณสามารถปกป้องปลายทาง (endpoints) ของคุณได้ ในขณะที่ยังคงรักษาโค้ดเบสให้สะอาดและดูแลรักษาง่าย

ในคู่มือนี้ เราจะมาดูวิธีการใช้งานการตรวจสอบสิทธิ์แบบ JWT ใน API ของ Node.js โดยใช้ Express, MongoDB และเครื่องมือต่างๆ เช่น jsonwebtoken, bcrypt, Joi และ dotenv และเราจะมาดูวิธีการตรวจสอบความถูกต้องของโทเค็นโดยใช้เอนด์พอยต์ JWKS จากเซิร์ฟเวอร์การอนุญาตในสถานการณ์ที่เน้นองค์กรมากขึ้นด้วย คุณจะได้เรียนรู้วิธีการออกแบบโครงสร้างโปรเจ็กต์ สร้างโมเดลและเส้นทาง สร้างและตรวจสอบโทเค็น เพิ่มมิดเดิลแวร์การตรวจสอบสิทธิ์ และเชื่อมโยงทุกอย่างเข้าด้วยกัน เพื่อให้เฉพาะผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์เท่านั้นจึงจะสามารถเข้าถึงทรัพยากรที่ได้รับการป้องกันได้

JSON Web Tokens (JWT) มอบอะไรให้กับ API ของคุณใน Node.js บ้าง

JSON Web Tokens (JWT) เป็นโทเค็นขนาดกะทัดรัด ปลอดภัยต่อ URL ซึ่งประกอบด้วยชุดข้อมูลอ้างอิง และช่วยให้สองฝ่ายสามารถแลกเปลี่ยนข้อมูลที่ได้รับการตรวจสอบสิทธิ์ได้โดยไม่ต้องเก็บสถานะเซสชันฝั่งเซิร์ฟเวอร์ ในบริบทของ API Node.js หมายความว่า เมื่อผู้ใช้ลงชื่อเข้าใช้และคุณออก JWT แล้ว การร้องขอครั้งต่อๆ ไปทั้งหมดสามารถตรวจสอบได้โดยแบ็กเอนด์ของคุณโดยใช้เพียงโทเค็นและคีย์ลับหรือคีย์สาธารณะ ซึ่งมีประสิทธิภาพในการปรับขนาดได้ดีกว่าเซสชันเซิร์ฟเวอร์แบบดั้งเดิมมาก

โดยทั่วไป JWT ประกอบด้วยสามส่วน ได้แก่ ส่วนหัว ส่วนข้อมูล และส่วนลายเซ็น ซึ่งทั้งหมดเข้ารหัสด้วย Base64URL และคั่นด้วยจุด ตัวอย่างเช่น xxxxx.yyyyy.zzzzz. โดยปกติแล้ว ส่วนหัวจะระบุอัลกอริทึมและประเภทของโทเค็น ส่วนข้อมูลจะประกอบด้วยข้อมูลที่เกี่ยวข้องกับผู้ใช้ เช่น รหัสประจำตัว บทบาท หรือสิทธิ์ และลายเซ็นจะรับรองความสมบูรณ์เพื่อป้องกันไม่ให้มีการปลอมแปลงโทเค็นโดยที่ตรวจไม่พบ

เมื่อนำ JWT มาใช้ใน API ของ Node.js โดยปกติแล้วคุณจะใช้โทเค็นเป็น Bearer Token ใน Authorization ส่วนหัว HTTP เช่น Authorization: Bearer <token>จากนั้นจึงถอดรหัสและตรวจสอบความถูกต้องภายในมิดเดิลแวร์หรือตัวจัดการเส้นทางของ Express ของคุณ หากโทเค็นถูกต้อง คุณสามารถแนบข้อมูลที่ถอดรหัสแล้วไปยังออบเจ็กต์คำขอและนำไปใช้ในภายหลังสำหรับการตัดสินใจเกี่ยวกับการอนุญาตหรือเพื่อปรับแต่งการตอบกลับได้

จุดเด่นที่สำคัญอย่างหนึ่งของ JWT คือไม่ขึ้นอยู่กับภาษาใดภาษาหนึ่ง และได้รับการสนับสนุนอย่างกว้างขวางในระบบนิเวศต่างๆ ซึ่งทำให้เป็นตัวเลือกที่ยอดเยี่ยมสำหรับการรักษาความปลอดภัย API ที่ใช้งานโดย React, Vue, แอปพลิเคชันมือถือ หรือไคลเอ็นต์ของบุคคลที่สามใดๆ เมื่อผนวกรวมกับการตรวจสอบความถูกต้องที่รัดกุมและการจัดการคีย์ที่เหมาะสม จะทำให้บริการ Node.js สามารถเข้าร่วมในสถาปัตยกรรมที่ใช้ OAuth 2.0 และ OpenID Connect ได้อย่างราบรื่น

ภาพรวมโครงการ: API ที่ใช้ Node.js พร้อมการตรวจสอบสิทธิ์ด้วย JWT

ลองนึกภาพ API ที่เรียบง่ายแต่สมจริงด้วย Node.js ซึ่งผู้ใช้สามารถลงทะเบียน เข้าสู่ระบบ และเข้าถึงปลายทางที่ได้รับการป้องกันได้ก็ต่อเมื่อแสดง JWT ที่ถูกต้องเท่านั้น เราจะใช้ Express สำหรับการกำหนดเส้นทาง, Mongoose สำหรับการเชื่อมต่อกับ MongoDB, jsonwebtoken สำหรับการสร้างและตรวจสอบโทเค็น, bcrypt สำหรับการเข้ารหัสรหัสผ่านอย่างปลอดภัย, Joi สำหรับการตรวจสอบความถูกต้องของข้อมูลขาเข้า และ dotenv สำหรับการจัดการการกำหนดค่า

โครงสร้างโฟลเดอร์ที่เป็นระเบียบจะช่วยให้เข้าใจสิ่งต่างๆ ได้ง่ายขึ้นเมื่อโปรเจ็กต์เติบโตขึ้น ดังนั้นแทนที่จะใส่ทุกอย่างไว้ในไฟล์เดียว เราจะกำหนดโครงสร้างพื้นฐานโดยแยกโมดูลต่างๆ ออกเป็นส่วนๆ สำหรับการตั้งค่า ฐานข้อมูล โมเดล เส้นทาง และมิดเดิลแวร์ วิธีการแบบแยกส่วนนี้ยังช่วยให้การทดสอบหน่วยเฉพาะส่วนของกระบวนการตรวจสอบสิทธิ์ทำได้ง่ายขึ้นอีกด้วย

โดยสรุปแล้ว API จะเปิดเผยชุดของเอนด์พอยต์ REST สำหรับการลงทะเบียนและเข้าสู่ระบบของผู้ใช้ รวมถึงทรัพยากรที่ได้รับการป้องกันอย่างน้อยหนึ่งรายการ ซึ่งสามารถเข้าถึงได้ก็ต่อเมื่อมี JWT ที่ถูกต้องในส่วนหัวของคำขอเท่านั้น ในระหว่างนี้ เราจะได้เรียนรู้วิธีการตรวจสอบความถูกต้องของข้อมูลที่ส่งมาในคำขอ การแฮชและเปรียบเทียบรหัสผ่าน การสร้างโทเค็นที่มีรหัสผู้ใช้ และการผสานรวมมิดเดิลแวร์การตรวจสอบสิทธิ์ที่ตรวจสอบโทเค็นในการโทรเข้า

รูปแบบเดียวกันนี้สามารถขยายไปใช้กับระบบที่ซับซ้อนมากขึ้นได้ รวมถึงระบบที่ผสานรวมกับเซิร์ฟเวอร์การอนุญาตภายนอกและใช้เอนด์พอยต์ JWKS เพื่อตรวจสอบความถูกต้องของโทเค็นการเข้าถึงที่เข้ามาจากไคลเอ็นต์ OAuth 2.0 สถานการณ์ที่สองนั้นพบได้บ่อยเป็นพิเศษเมื่อคุณมอบหมายการตรวจสอบสิทธิ์ให้กับผู้ให้บริการข้อมูลประจำตัว หรือจำเป็นต้องรองรับการเข้าสู่ระบบครั้งเดียว (Single Sign-On) ในหลายบริการ

ก่อนที่เราจะลงลึกในรายละเอียดของการใช้งาน เรามาทำความเข้าใจส่วนประกอบสำคัญของสภาพแวดล้อมที่เราจะใช้ และเหตุผลว่าทำไมแต่ละส่วนประกอบจึงมีความสำคัญต่อการจัดการ JWT อย่างปลอดภัยใน Node.js กันก่อน

ส่วนประกอบหลักที่จำเป็นสำหรับการตรวจสอบสิทธิ์ JWT ใน Node.js

Express เป็นแกนหลักของ API Node.js จำนวนมาก โดยเป็นเฟรมเวิร์กที่เรียบง่ายแต่ยืดหยุ่นสำหรับการกำหนดเส้นทาง มิดเดิลแวร์ และการจัดการ HTTP ในกรณีของเรา Express จะทำหน้าที่เป็นแพลตฟอร์มที่เราใช้ในการลงทะเบียนเส้นทางต่างๆ เช่น /api/users or /api/authและในส่วนที่เราเสียบมิดเดิลแวร์สำหรับการตรวจสอบ JWT เพื่อปกป้องปลายทางข้อมูลที่ละเอียดอ่อน

Mongoose เป็นไลบรารีสำหรับการสร้างแบบจำลองข้อมูลเชิงวัตถุ (Object Data Modeling หรือ ODM) ซึ่งช่วยให้การโต้ตอบกับ MongoDB ง่ายขึ้นผ่านทางสคีมาและโมเดล แทนที่จะทำงานกับคำสั่ง SQL โดยตรง เราจะใช้มันเพื่อกำหนด User สร้างแบบจำลองที่มีคุณสมบัติ เช่น ชื่อ อีเมล และรหัสผ่าน และบันทึกหรือดึงเอกสารเหล่านี้จากฐานข้อมูลในลักษณะที่ปลอดภัยต่อประเภทข้อมูล

การขอ jsonwebtoken ไลบรารีนี้เป็นตัวเลือกมาตรฐานใน Node.js สำหรับการสร้างและตรวจสอบ JWT โดยใช้คีย์ลับหรือคีย์สาธารณะ ในระหว่างการเข้าสู่ระบบ เราจะลงนามในโทเค็นที่ฝังรหัสผู้ใช้ (และข้อมูลอื่นๆ ที่เราต้องการ) และในภายหลังเราจะตรวจสอบโทเค็นนั้นบนเส้นทางที่ได้รับการป้องกัน โดยจะปฏิเสธคำขอใดๆ ที่มีโทเค็นที่ไม่ถูกต้อง ผิดรูปแบบ หรือหมดอายุ

เพื่อความปลอดภัยของรหัสผ่าน bcrypt จะถูกใช้เพื่อเข้ารหัสรหัสผ่านที่เป็นข้อความธรรมดาก่อนจัดเก็บ และใช้เปรียบเทียบข้อมูลประจำตัวที่ให้มากับค่าที่เข้ารหัสไว้ในระหว่างการตรวจสอบสิทธิ์ นี่เป็นเรื่องสำคัญมาก เพราะการจัดเก็บรหัสผ่านแบบดิบๆ หรือการใช้กลยุทธ์การแฮชที่อ่อนแอ จะทำให้ผู้ใช้ของคุณตกอยู่ในความเสี่ยงอย่างมากในกรณีที่ฐานข้อมูลรั่วไหล ในขณะที่ bcrypt นำเสนอโซลูชันที่ได้รับการพิสูจน์แล้วและผ่านการทดสอบมาแล้ว

Joi มีบทบาทสำคัญในการตรวจสอบความถูกต้องของข้อมูลที่เข้ามาที่ขอบเขต API โดยอธิบายโครงสร้างข้อมูลสำหรับอ็อบเจ็กต์และตรวจสอบว่าเพย์โหลดคำขอแต่ละรายการทำงานได้ตามที่คาดไว้ ตัวอย่างเช่น เราสามารถกำหนดได้ว่าอีเมลต้องมีรูปแบบที่ถูกต้อง รหัสผ่านต้องมีความยาวขั้นต่ำ และบางช่องข้อมูลเป็นช่องที่ต้องกรอก ซึ่งจะช่วยลดโอกาสที่ข้อมูลที่ไม่ถูกต้องหรือเป็นอันตรายจะแทรกซึมเข้ามาในระบบของเราได้อย่างมาก

สุดท้ายนี้ dotenv ช่วยให้เราสามารถโหลดตัวแปรสภาพแวดล้อมจากไฟล์ได้ .env ไฟล์ดังกล่าวเก็บความลับต่างๆ เช่น คีย์ลงนาม JWT, URL ของฐานข้อมูล หรือการตั้งค่าต่างๆ ไว้ภายนอกซอร์สโค้ด วิธีนี้ช่วยหลีกเลี่ยงการใส่ค่าที่ละเอียดอ่อนลงไปในโค้ดโดยตรง และส่งเสริมการแยกส่วนระหว่างการตั้งค่าสำหรับการพัฒนา การทดสอบ และการใช้งานจริงได้ดียิ่งขึ้น

การตั้งค่าเซิร์ฟเวอร์และสภาพแวดล้อมของ Express

จุดเริ่มต้นของ API ของเรามักจะเป็น index.js ไฟล์ที่เราใช้ในการเริ่มต้นระบบ Express ลงทะเบียนมิดเดิลแวร์ และกำหนดเส้นทาง (route definition) ในไฟล์นี้ เราจะต้องการการตั้งค่าฐานข้อมูล โมดูลการกำหนดเส้นทาง และมิดเดิลแวร์ระดับโลกต่างๆ เช่น การแยกวิเคราะห์เนื้อหา JSON หรือ CORS

หลังจากโหลดส่วนประกอบที่จำเป็นเสร็จแล้ว ควรเรียกใช้ฟังก์ชันดังกล่าวทันที require("dotenv").config() ดังนั้นตัวแปรสภาพแวดล้อมจาก .env ไฟล์จะพร้อมใช้งานผ่านทาง process.env. ซึ่งรวมถึงกุญแจต่างๆ เช่น JWT_PRIVATE_KEY, MONGO_URI หรือพอร์ตที่เซิร์ฟเวอร์จะรับฟัง ซึ่งช่วยให้การกำหนดค่ามีความยืดหยุ่นและปลอดภัย

แอป Express เองโดยทั่วไปจะใช้ app.use(express.json()) เพื่อแยกวิเคราะห์เนื้อหาคำขอ JSON และจะติดตั้งเราเตอร์สำหรับคำนำหน้า URL เฉพาะ เช่น app.use("/api/users", usersRouter) และ app.use("/api/auth", authRouter). การแยกส่วนนี้ช่วยให้เส้นทางที่เกี่ยวข้องกับการตรวจสอบสิทธิ์และการจัดการผู้ใช้แยกออกจากส่วนอื่นๆ ของ API

เมื่อตั้งค่าสภาพแวดล้อมและเรียกใช้ Express แล้ว ขั้นตอนต่อไปคือการเชื่อมต่อฐานข้อมูล MongoDB ผ่านโมดูลเฉพาะ ซึ่งมักจะเป็น db.js ไฟล์ที่เราใช้กำหนดตรรกะการเชื่อมต่อ

การกำหนดค่า MongoDB ด้วย Mongoose

ตัว Vortex Indicator ได้ถูกนำเสนอลงในนิตยสาร db.js โดยทั่วไปแล้ว เราจะนำเข้าโมดูล Mongoose และเรียกใช้โมดูลนั้น mongoose.connect() โดยเก็บสตริงการเชื่อมต่อ MongoDB ไว้ในตัวแปรสภาพแวดล้อม นอกจากนี้ เรายังสามารถกำหนดค่าตัวเลือกต่างๆ เช่น ตรรกะการลองใหม่ โครงสร้างเครือข่ายแบบรวม หรือการจัดการกลุ่มการเชื่อมต่อ เพื่อให้มั่นใจได้ถึงการทำงานที่มีเสถียรภาพในสภาพแวดล้อมการใช้งานจริง

เป็นเรื่องปกติที่จะบันทึกข้อความเมื่อการเชื่อมต่อสำเร็จและจัดการข้อผิดพลาดอย่างเหมาะสม เพื่อให้หากไม่สามารถเข้าถึง MongoDB ได้ API จะเริ่มต้นทำงานพร้อมกับการวินิจฉัยที่ชัดเจน ในแอปพลิเคชันแบบเต็มรูปแบบ คุณอาจเลือกที่จะยุติกระบวนการทำงานหากการเชื่อมต่อฐานข้อมูลล้มเหลว เนื่องจากเส้นทางการทำงานหลายเส้นทางขึ้นอยู่กับการเชื่อมต่อนี้

เมื่อ db.js ไฟล์ถูกใช้งานแล้ว เราจึงนำเข้าจาก index.js และเรียกใช้ฟังก์ชันนี้ตั้งแต่ช่วงเริ่มต้นการทำงานของแอปพลิเคชัน เพื่อให้แน่ใจว่า API ของเราเชื่อมต่อกับฐานข้อมูลแล้วก่อนที่จะประมวลผลคำขอใดๆ การแยกส่วนนี้ช่วยให้การกำหนดค่าแยกออกจากกันและสามารถนำกลับมาใช้ใหม่ได้ ในขณะที่ index.js ยังคงให้ความสำคัญกับข้อกังวลของ Express อยู่

เมื่อเชื่อมต่อฐานข้อมูลเรียบร้อยแล้ว เราก็สามารถดำเนินการต่อในการสร้างแบบจำลองข้อมูลที่จะขับเคลื่อนระบบการตรวจสอบสิทธิ์ของเรา ซึ่งเริ่มต้นด้วยการกำหนดโครงสร้างและแบบจำลองของผู้ใช้

การสร้างโมเดลผู้ใช้ด้วยการรองรับ JWT

การขอ User แบบจำลอง ซึ่งโดยปกติจะวางไว้ใน /models/user.jsกำหนดโครงสร้างของเอกสารผู้ใช้ที่จัดเก็บไว้ใน MongoDB และรวบรวมพฤติกรรมที่เกี่ยวข้องกับการตรวจสอบสิทธิ์ อย่างน้อยที่สุด เราจะรวมคุณสมบัติต่างๆ เช่น name, email และ passwordและเราอาจเพิ่มการประทับเวลา บทบาท หรือข้อมูลเมตาอื่นๆ ตามความจำเป็นได้ด้วย

รูปแบบทั่วไปคือการกำหนดให้ช่องอีเมลเป็นช่องที่ไม่ซ้ำกันและจำเป็นต้องกรอก เพื่อให้แน่ใจว่าไม่มีผู้ใช้สองคนสามารถลงทะเบียนด้วยที่อยู่อีเมลเดียวกันได้ ในทำนองเดียวกัน ช่องรหัสผ่านจะไม่เก็บค่าข้อความธรรมดา แต่จะเก็บค่าแฮช bcrypt ที่สร้างขึ้นเมื่อลงทะเบียนหรือเมื่อผู้ใช้อัปเดตข้อมูลประจำตัวแทน

การตัดสินใจด้านการออกแบบที่น่าสนใจและใช้งานได้จริงอย่างหนึ่งคือ การเพิ่มเมธอดในสคีมาผู้ใช้เพื่อสร้าง JWT ซึ่งจะใช้ ID ของผู้ใช้เป็นเพย์โหลดและลงนามด้วยคีย์ลับที่กำหนดไว้ในสภาพแวดล้อม สามารถเรียกใช้เมธอดนี้ระหว่างการเข้าสู่ระบบเพื่อสร้างโทเค็นเฉพาะสำหรับผู้ใช้รายนั้น และจะเก็บตรรกะการสร้างโทเค็นไว้ร่วมกับโมเดลที่เป็นเจ้าของข้อมูลระบุตัวตน

เมื่อผนวกรวมกับตัวช่วยตรวจสอบความถูกต้องที่ใช้ Joi โมเดลผู้ใช้จะกลายเป็นส่วนสำคัญสำหรับทุกสิ่งที่เกี่ยวข้องกับข้อมูลระบุตัวตน ได้แก่ การอธิบายรูปแบบของข้อมูลผู้ใช้ การตรวจสอบความถูกต้องของข้อมูลที่เข้ามา และการสร้างโทเค็นที่ใช้โดยส่วนอื่นๆ ของ API

จากตรงนี้ เราสามารถนำเส้นทางที่รับผิดชอบในการลงทะเบียนบัญชีใหม่และการตรวจสอบสิทธิ์ผู้ใช้ที่มีอยู่มาใช้ โดยใช้โมเดลผู้ใช้ bcrypt และ Joi ร่วมกัน

การสร้างเส้นทางการลงทะเบียน

โดยปกติแล้วตรรกะการลงทะเบียนจะอยู่ในโมดูลเส้นทาง เช่น /routes/users.jsโดยที่เรากำหนดจุดสิ้นสุดไว้ เช่น POST /api/users เพื่อจัดการกับคำขอลงทะเบียนที่เข้ามา เส้นทางนี้จะตรวจสอบความถูกต้องของข้อมูลที่ส่งมาโดยใช้ Joi ตรวจสอบว่าอีเมลนั้นถูกใช้งานอยู่แล้วหรือไม่ เข้ารหัสรหัสผ่าน สร้างผู้ใช้ และบันทึกข้อมูลลงในฐานข้อมูล

ก่อนที่จะบันทึกข้อมูลใดๆ เราสามารถใช้ Joi schema ที่บังคับใช้ข้อกำหนดต่างๆ เช่น ชื่อและอีเมลที่จำเป็น รูปแบบอีเมลที่ถูกต้อง และความยาวรหัสผ่านขั้นต่ำ หากการตรวจสอบความถูกต้องล้มเหลว เส้นทางจะตอบกลับด้วยรหัสสถานะข้อผิดพลาดและข้อความที่เหมาะสม เพื่อป้องกันไม่ให้ข้อมูลที่ไม่ถูกต้องไปถึงส่วนตรรกะทางธุรกิจ

หากอีเมลนั้นยังไม่มีอยู่ เราจะสร้างค่า salt ของ bcrypt และทำการแฮชรหัสผ่าน จากนั้นแทนที่รหัสผ่านเดิมด้วยรหัสผ่านที่แฮชแล้วในอ็อบเจ็กต์ผู้ใช้ ค่าแฮชนี้เองที่จะถูกจัดเก็บไว้ใน MongoDB ซึ่งช่วยลดผลกระทบจากการรั่วไหลของข้อมูลได้อย่างมาก

หลังจากบันทึกผู้ใช้ใหม่แล้ว บางระบบเลือกที่จะสร้าง JWT ทันทีและส่งคืนในส่วนหัวหรือเนื้อหาของการตอบกลับ เพื่อให้ผู้ใช้ถือว่าได้รับการตรวจสอบสิทธิ์แล้วทันทีหลังจากการลงทะเบียน API อื่นๆ อาจต้องมีการเข้าสู่ระบบแยกต่างหาก ขึ้นอยู่กับข้อกำหนดด้านความปลอดภัยของระบบนั้นๆ

เมื่อการลงทะเบียนเสร็จสมบูรณ์แล้ว เส้นทางการเข้าสู่ระบบที่เกี่ยวข้องสามารถนำตรรกะการตรวจสอบความถูกต้องแบบเดียวกันมาใช้ซ้ำได้ โดยเน้นที่การตรวจสอบข้อมูลประจำตัวและการออกโทเค็น

การใช้งานเส้นทางการเข้าสู่ระบบและการสร้างโทเค็น

โดยทั่วไปแล้ว ขั้นตอนการเข้าสู่ระบบจะดำเนินการใน /routes/auth.jsโดยมีจุดสิ้นสุดเช่น POST /api/auth ซึ่งจะได้รับอีเมลและรหัสผ่านในส่วนเนื้อหาของคำขอ เส้นทางนี้ใช้ Joi อีกครั้งเพื่อให้แน่ใจว่าทั้งสองช่องข้อมูลมีอยู่ครบถ้วนและมีโครงสร้างที่ถูกต้องก่อนที่จะพยายามยืนยันตัวตนผู้ใช้

หลังจากตรวจสอบความถูกต้องแล้ว เส้นทางนี้จะค้นหาฐานข้อมูลผู้ใช้ที่มีอีเมลที่ระบุ และหากพบ ระบบจะใช้ bcrypt เพื่อเปรียบเทียบรหัสผ่านที่ให้มากับแฮชที่จัดเก็บไว้ หากการเปรียบเทียบไม่สำเร็จ คำขอจะถูกปฏิเสธพร้อมข้อความแสดงข้อผิดพลาดที่เหมาะสม มิเช่นนั้น เราจะดำเนินการออกโทเค็นต่อไป

เมื่อการตรวจสอบสิทธิ์สำเร็จ เราจะเรียกใช้เมธอดสร้างโทเค็นที่กำหนดไว้ในโมเดลผู้ใช้ ซึ่งจะสร้าง JWT ที่ฝังตัวระบุของผู้ใช้ (และอาจรวมถึงข้อมูลอื่นๆ) และลงนามด้วยรหัสลับ จากนั้นโทเค็นนี้จะถูกส่งไปยังไคลเอ็นต์ โดยมักจะอยู่ในส่วนเนื้อหาของการตอบกลับหรือส่วนหัวที่กำหนดเอง ซึ่งส่วนหน้าหรือผู้ใช้งานภายนอกจะจัดเก็บและนำกลับมาใช้ใหม่สำหรับการร้องขอในอนาคต

จากมุมมองฝั่งไคลเอ็นต์ การเรียกใช้งานปลายทางที่ได้รับการป้องกันทุกครั้งหลังจากนั้นจะรวม JWT นี้ไว้ด้วย Authorization ส่วนหัวเป็นโทเค็นแบบ Bearer ซึ่งเป็นสิ่งที่มิดเดิลแวร์ของเราจะมองหาอย่างแน่นอน ในฝั่งเซิร์ฟเวอร์ การมีมิดเดิลแวร์สำหรับการตรวจสอบสิทธิ์โดยเฉพาะจะช่วยให้เราไม่ต้องเขียนตรรกะการตรวจสอบโทเค็นซ้ำในทุกเส้นทาง

ก่อนที่จะเจาะลึกไปถึงมิดเดิลแวร์นั้น เราควรทราบก่อนว่ารูปแบบเดียวกันนี้สามารถทำงานร่วมกับ React หรือเฟรมเวิร์ก SPA อื่นๆ ได้อย่างลงตัว โดยที่กระบวนการที่ใช้ JWT นั้นมักใช้สำหรับการตรวจสอบสิทธิ์และการอนุญาตแบบง่ายๆ

การสร้างมิดเดิลแวร์การตรวจสอบสิทธิ์เพื่อปกป้องเส้นทาง

มิดเดิลแวร์การตรวจสอบสิทธิ์ มักถูกนำไปใช้ใน /middleware/auth.jsทำหน้าที่เป็นผู้เฝ้าประตูสำหรับเส้นทางใดๆ ที่ต้องการการตรวจสอบสิทธิ์ โดยจะดักจับคำขอต่างๆ ก่อนที่จะไปถึงตัวจัดการเส้นทาง หน้าที่หลักของมันคือการอ่าน JWT จาก Authorization ตรวจสอบส่วนหัวและแทรกข้อมูลที่ถอดรหัสแล้วลงในอ็อบเจ็กต์คำขอเพื่อใช้ในภายหลัง

มิดเดิลแวร์จะเริ่มต้นด้วยการตรวจสอบว่า Authorization ส่วนหัวมีอยู่และเป็นไปตามที่คาดไว้ Bearer <token> รูปแบบไม่ถูกต้อง หากโทเค็นหายไปหรือมีรูปแบบผิดปกติ ระบบจะตอบกลับด้วยรหัสสถานะไม่ได้รับอนุญาตทันที วิธีนี้ช่วยป้องกันไม่ให้คำขอที่ไม่ได้รับการป้องกันหลุดเข้าไปในปลายทางที่มีการรักษาความปลอดภัยโดยไม่ตั้งใจ

เมื่อมีโทเค็นอยู่ มิดเดิลแวร์จะเรียกใช้งาน jwt.verify() (จาก jsonwebtoken (โดยใช้ไลบรารี) โดยส่งโทเค็นและรหัสลับหรือรหัสสาธารณะที่ใช้ในการลงนาม หากการตรวจสอบล้มเหลวเนื่องจากการหมดอายุ ลายเซ็นไม่ตรงกัน หรือปัญหาอื่นใด มิดเดิลแวร์จะตอบกลับด้วยข้อผิดพลาด มิเช่นนั้นจะดักจับข้อมูลที่ถอดรหัสแล้ว

การใช้งานหลายๆ วิธีจะแนบข้อมูลที่ถอดรหัสแล้วนี้เข้ากับ... req.user หรือคุณสมบัติที่คล้ายคลึงกัน เพื่อให้ตัวจัดการเส้นทางปลายทางสามารถเข้าถึงข้อมูลที่เกี่ยวข้องกับผู้ใช้ได้โดยไม่ต้องทำการวิเคราะห์หรือตรวจสอบโทเค็นซ้ำอีกครั้ง สุดท้ายนี้ มิดเดิลแวร์จะเรียกใช้งาน next() เพื่อส่งการควบคุมไปยังฟังก์ชันถัดไปในไปป์ไลน์ของ Express

ด้วยการผสานรวมมิดเดิลแวร์นี้เข้ากับการกำหนดเส้นทาง เราสามารถกำหนดให้บางเอนด์พอยต์เป็นสาธารณะและบางเอนด์พอยต์เป็นที่ได้รับการป้องกันได้อย่างง่ายดาย เพียงแค่เพิ่มมิดเดิลแวร์ลงในห่วงโซ่การจัดการคำขอสำหรับเส้นทางเหล่านั้น

การเข้าถึงทรัพยากรที่ได้รับการปกป้องด้วย JWT

หลังจากใช้งานระบบตรวจสอบสิทธิ์แล้ว กรณีการใช้งานทั่วไปอย่างหนึ่งคือ การจัดเตรียมเส้นทางที่ดึงข้อมูลโปรไฟล์ผู้ใช้ปัจจุบันหรือรายชื่อผู้ใช้ ซึ่งสามารถเข้าถึงได้เฉพาะผู้เรียกใช้งานที่แสดงโทเค็นที่ถูกต้องเท่านั้น ตัวอย่างเช่นใน /routes/users.jsอาจจะมี GET /api/users/me เอนด์พอยต์ที่ส่งคืนข้อมูลเกี่ยวกับผู้ใช้ที่เข้าสู่ระบบ

เพื่อป้องกันเส้นทางนี้ เราจึงแนบ middleware สำหรับการตรวจสอบสิทธิ์ไว้ เพื่อให้คำขอใดๆ ที่เข้ามาต้องมี JWT ที่ถูกต้อง มิเช่นนั้น middleware จะยุติคำขอนั้นก่อนที่ handler จะทำงานจริง เนื่องจากข้อมูลที่ถอดรหัสแล้วได้ถูกแนบไว้กับแล้ว req.userโดยตัวจัดการสามารถดึงรหัสผู้ใช้ได้โดยตรงจากโทเค็นและสอบถามฐานข้อมูลตามนั้นได้

รูปแบบนี้ทำให้มั่นใจได้ว่าตรรกะทางธุรกิจจะไม่สนใจว่าการตรวจสอบสิทธิ์ดำเนินการอย่างไร มันจะเชื่อถือเพียงแค่การมีอยู่ของเพย์โหลดที่ได้รับการตรวจสอบแล้ว และมุ่งเน้นไปที่การดึงหรือแก้ไขข้อมูลโดเมน ในการตั้งค่าขั้นสูง คุณยังสามารถฝังบทบาท สิทธิ์ หรือขอบเขตไว้ในโทเค็น และใช้สิ่งเหล่านั้นเพื่อควบคุมการตรวจสอบการอนุญาตในตัวจัดการได้อีกด้วย

จากมุมมองของผู้บริโภค ผู้เรียกใช้งานจะเข้าถึงเอนด์พอยต์ล็อกอินก่อนเพื่อรับโทเค็น จากนั้นจึงนำโทเค็นนั้นไปใช้ในการร้องขอครั้งต่อๆ ไปยังเอนด์พอยต์ที่มีการป้องกันเหล่านี้ ซึ่งมักมาจาก SPA เช่น React แอปพลิเคชันมือถือ หรือการผสานรวมระหว่างแบ็กเอนด์ โดยรวมแล้วประสบการณ์การใช้งานจะราบรื่น หากข้อความแสดงข้อผิดพลาดมีความชัดเจนเมื่อโทเค็นหมดอายุหรือไม่ถูกต้อง

มาถึงตรงนี้ เราได้กล่าวถึงการตั้งค่า JWT แบบครบวงในตัวเอง โดยใช้รหัสลับที่จัดเก็บไว้ในระบบของเรา .env นอกจากไฟล์แล้ว ระบบการผลิตจำนวนมากยังผสานรวมกับเซิร์ฟเวอร์การอนุญาตภายนอกและใช้เอนด์พอยต์ JWKS เพื่อตรวจสอบโทเค็น ซึ่งนั่นคือจุดที่มิดเดิลแวร์ Express สำหรับ API ที่มีการรักษาความปลอดภัยด้วย OAuth เข้ามามีบทบาท

การใช้ JWKS Endpoint เพื่อตรวจสอบความถูกต้องของ JWT ใน Node.js

ในสถาปัตยกรรมขั้นสูง โดยเฉพาะอย่างยิ่งที่ใช้ OAuth 2.0 และ OpenID Connect นั้น API ของ Node.js มักจะได้รับโทเค็นการเข้าถึงที่ออกโดยเซิร์ฟเวอร์การอนุญาตภายนอก แทนที่จะสร้าง JWT ด้วยตนเอง ในกรณีนี้ API จะต้องตรวจสอบความถูกต้องของโทเค็นที่ลงนามด้วยคีย์แบบอสมมาตร ซึ่งโดยทั่วไปคือ RSA หรือ EC โดยที่เซิร์ฟเวอร์การอนุญาตเท่านั้นที่เป็นผู้ถือคีย์ส่วนตัว

วิธีแก้ปัญหาที่นิยมใช้กันคือการใช้ไลบรารีมิดเดิลแวร์ของ Express ที่ดึงชุดคีย์เว็บ JSON (JWKS) จากเอนด์พอยต์ที่กำหนดค่าไว้ซึ่งเปิดเผยโดยเซิร์ฟเวอร์การอนุญาต เอนด์พอยต์ JWKS นั้นเปิดเผยคีย์สาธารณะในรูปแบบมาตรฐาน ทำให้ API สามารถตรวจสอบลายเซ็น JWT ที่เข้ามาได้โดยไม่ต้องจัดการคีย์ส่วนตัวเลย

ตัวอย่างเช่น คุณอาจติดตั้งแพ็กเกจเช่น express-oauth-jwt และกำหนดค่าด้วย URL ของ JWKS ดังนี้ https://idsvr.example.com/oauth/v2/oauth-anonymous/jwksจากนั้นจึงเชื่อมต่อ middleware เข้ากับเส้นทาง API ของ Node.js ของคุณ เมื่อผสานรวมเข้ากับระบบแล้ว มิดเดิลแวร์จะจัดการงานตรวจสอบความถูกต้องของโทเค็นระดับต่ำส่วนใหญ่โดยอัตโนมัติ

เมื่อตั้งค่าเช่นนั้นแล้ว ห้องสมุดจะค้นหา... kid (รหัสคีย์) จากส่วนหัวของ JWT จะดาวน์โหลดคีย์สาธารณะที่เหมาะสมจากปลายทาง JWKS (หากยังไม่ได้แคชไว้) และตรวจสอบลายเซ็นโดยใช้คีย์นั้น นอกจากนี้ยังตรวจสอบวันหมดอายุของโทเค็น ผู้ออกโทเค็น กลุ่มเป้าหมาย และข้อมูลมาตรฐานอื่นๆ ขึ้นอยู่กับการตั้งค่าตัวเลือกของคุณ

หลังจากตรวจสอบความถูกต้องสำเร็จแล้ว JWT ที่ถูกแยกวิเคราะห์และข้อมูลที่อยู่ในนั้นจะพร้อมใช้งานบน Express request อ็อบเจ็กต์นี้จะช่วยให้ตัวจัดการของคุณสามารถตรวจสอบขอบเขต ตัวระบุผู้ใช้ หรือคุณลักษณะที่กำหนดเองเพื่อวัตถุประสงค์ในการอนุญาตและการบันทึกข้อมูลได้ หากเกิดข้อผิดพลาดใดๆ (เช่น โทเค็นหมดอายุหรือลายเซ็นไม่ตรงกัน) มิดเดิลแวร์จะตอบกลับด้วยรหัสข้อผิดพลาด HTTP ที่เหมาะสมและระบุเหตุผลไว้ในข้อความตอบกลับ WWW-Authenticate ส่วนหัว

ขอบเขต การอ้างสิทธิ์ และตรรกะการอนุญาตใน API ของคุณ

เมื่อ API ของ Node.js เชื่อถือ JWT แล้ว ไม่ว่าจะเพราะลงนามโดยตรงหรือเพราะมิดเดิลแวร์ที่ใช้ JWKS ตรวจสอบความถูกต้องแล้ว ขั้นตอนต่อไปคือการใช้ข้อมูลอ้างอิงและขอบเขตของ JWT เพื่อใช้ในการอนุญาตสิทธิ์ นี่คือจุดที่คุณจะก้าวข้ามการตรวจสอบสิทธิ์แบบธรรมดา และเริ่มให้หรือปฏิเสธการเข้าถึงโดยพิจารณาจากสิ่งที่ผู้ใช้ได้รับอนุญาตให้ทำได้

โดยทั่วไป ขอบเขตจะแสดงถึงสิทธิ์การเข้าถึงแบบหยาบๆ เช่น read:users or write:ordersและโดยปกติจะรวมอยู่ใน JWT ภายใต้การเรียกร้องเช่น scope or scopes. API สามารถตรวจสอบได้ว่ามีขอบเขตที่ต้องการอยู่หรือไม่ก่อนที่จะประมวลผลคำขอที่เกี่ยวข้องกับข้อมูลทางธุรกิจบางอย่าง โดยจะส่งคืนข้อความตอบกลับว่า "ไม่ได้รับอนุญาต" หากไม่มีขอบเขตดังกล่าว

ในทำนองเดียวกัน การอ้างอิงข้อมูลต่างๆ เช่น รหัสผู้ใช้ อีเมล บทบาท หรือข้อมูลผู้เช่า ช่วยให้คุณสามารถกำหนดกฎเกณฑ์ที่ละเอียดขึ้นได้ ตัวอย่างเช่น การตรวจสอบให้แน่ใจว่าผู้ใช้เข้าถึงได้เฉพาะบันทึกของตนเอง หรือจำกัดการดำเนินการด้านการบริหารจัดการเฉพาะบทบาทที่กำหนดเท่านั้น ใน Express การเขียนมิดเดิลแวร์แบบกำหนดเองเพื่อตรวจสอบการอ้างสิทธิ์เหล่านี้ทำได้ง่ายมาก req.user และทำการตรวจสอบตามนโยบาย

ไลบรารีตรวจสอบ JWT บางตัวสำหรับ Express มีฮุกในตัวสำหรับตรวจสอบขอบเขตที่จำเป็นเป็นส่วนหนึ่งของตัวเลือก ทำให้ง่ายต่อการเชื่อมโยงแต่ละเส้นทางหรือเราเตอร์กับชุดสิทธิ์เฉพาะ แนวทางนี้ช่วยให้การจัดการสิทธิ์อนุญาตอยู่ใกล้กับการกำหนดเส้นทาง ซึ่งช่วยปรับปรุงความอ่านง่ายและความสามารถในการบำรุงรักษา

จากมุมมองด้านการออกแบบ โดยทั่วไปแล้ว การจัดการขอบเขตและข้อมูลอ้างอิงของ JWT ในรูปแบบของนโยบายแบบประกาศ (declarative policy) จะดีกว่าการกระจายสตริงที่เขียนตายตัวไว้ในโค้ด เพื่อหลีกเลี่ยงความไม่สอดคล้องกันและทำให้การเปลี่ยนแปลงรูปแบบความปลอดภัยในอนาคตทำได้ง่ายขึ้น

การทดสอบและการแก้ไขปัญหา API Node.js ที่ได้รับการป้องกันด้วย JWT

เมื่อเชื่อมต่อทุกอย่างเสร็จเรียบร้อยแล้ว คุณจะต้องทดสอบการเรียกใช้ API ของ Node.js โดยใช้และไม่ใช้ JWT ที่ถูกต้อง เพื่อยืนยันว่าการควบคุมการเข้าถึงทำงานได้อย่างถูกต้องตามที่คาดหวัง เครื่องมือพื้นฐานอย่าง curl, HTTPie หรือ Postman เหมาะสำหรับงานนี้ เพราะช่วยให้คุณตั้งค่าส่วนหัวและส่วนข้อมูลได้อย่างง่ายดาย

ขั้นตอนการทดสอบโดยทั่วไปจะเริ่มต้นด้วยการเรียกใช้เอนด์พอยต์การเข้าสู่ระบบเพื่อรับโทเค็น จากนั้นจึงส่งคำขอครั้งที่สองไปยังเส้นทางที่ได้รับการป้องกันพร้อมกับข้อมูล Authorization: Bearer <token> ชุดส่วนหัว หากการใช้งานของคุณถูกต้อง คำขอที่ได้รับอนุญาตควรจะสำเร็จ ในขณะที่การเรียกใช้โดยไม่มีโทเค็นหรือมีโทเค็นที่ไม่ถูกต้องควรถูกปฏิเสธ

เมื่อใช้ไลบรารีตรวจสอบความถูกต้องของ Express JWT ที่ผสานรวมกับเอนด์พอยต์ JWKS ปัญหาใดๆ เกี่ยวกับโทเค็นมักจะถูกแจ้งเตือนด้วยข้อความ 401 Unauthorized การตอบสนองและข้อมูลโดยละเอียดใน WWW-Authenticate ส่วนหัวของการตอบกลับ ตัวอย่างเช่น หากโทเค็นการเข้าถึงหมดอายุ ส่วนหัวของข้อมูลมักจะระบุรหัสข้อผิดพลาดและคำอธิบายที่เฉพาะเจาะจง

ข้อความแสดงข้อผิดพลาดโดยละเอียดเหล่านี้มีประโยชน์มากในระหว่างการพัฒนาและการแก้ไขข้อผิดพลาด แต่คุณควรระมัดระวังอย่าให้ข้อมูลภายในที่ละเอียดอ่อนเกินไปรั่วไหลลงในบันทึกการใช้งานจริงหรือการตอบกลับ การรวมศูนย์การบันทึกข้อมูลและการปกปิดหรือทำให้ข้อความบางส่วนเป็นแบบทั่วไป มักเป็นแนวคิดที่ดี โดยยังคงรักษาบริบทที่เพียงพอเพื่อให้ผู้ปฏิบัติงานสามารถวินิจฉัยปัญหาได้

การทดสอบอัตโนมัติและ JWT จำลองสามารถเพิ่มความมั่นใจได้มากยิ่งขึ้น ช่วยให้คุณตรวจสอบได้ว่าพฤติกรรมการอนุญาตมีความเสถียรเมื่อคุณเปลี่ยนแปลงเส้นทาง เพิ่มขอบเขต หรือปรับโครงสร้างตรรกะของมิดเดิลแวร์ใหม่

โดยรวมแล้ว API ของ Node.js ที่ผสานรวม Express, MongoDB, bcrypt, Joi และ JWT เข้าด้วยกัน—โดยอาจใช้ไลบรารีตรวจสอบความถูกต้องแบบ JWKS เพิ่มเติม—จะทำให้คุณมีรากฐานที่แข็งแกร่งสำหรับการรักษาความปลอดภัยของเอนด์พอยต์ ในขณะเดียวกันก็มีความยืดหยุ่นเพียงพอที่จะผสานรวมกับเฟรมเวิร์กฟรอนต์เอนด์สมัยใหม่ แอปพลิเคชันมือถือ และผู้ให้บริการข้อมูลประจำตัวระดับองค์กร

กระทู้ที่เกี่ยวข้อง: