Pre-requisite + Assignment

การพัฒนาระบบ Session-Based Auth และ REST API จัดการสินค้า

Part 1 ทบทวนความเข้าใจเชิงทฤษฎี พร้อมดาวน์โหลดโค้ดเดิม ก่อนเริ่มลงมือพัฒนาตามข้อกำหนดใน Part 2

Part 1 — คำถามทบทวนความเข้าใจ

คลิกที่หัวข้อเพื่อขยายดูคำตอบในแต่ละข้อ

1 Hashing vs Encryption แตกต่างกันอย่างไร

Hashing เป็นการแปลงข้อมูลให้เป็นค่า fixed-length แบบทางเดียว (one-way) ไม่สามารถถอดกลับเป็นข้อมูลเดิมได้ ใช้สำหรับเก็บข้อมูลที่ไม่ต้องนำกลับมาดูค่าจริง เช่น password เพราะแค่ต้องตรวจสอบว่าตรงกันหรือไม่ ตัวอย่าง: bcrypt, SHA-256

Encryption เป็นการเข้ารหัสข้อมูลแบบสองทาง (two-way) สามารถถอดรหัสกลับเป็นข้อมูลเดิมได้ด้วย key ใช้กับข้อมูลที่ต้องนำกลับมาใช้ เช่น เลขบัตรเครดิต, ข้อความใน chat ตัวอย่าง: AES, RSA

สรุป: Password ใช้ Hashing, ข้อมูลที่ต้องถอดกลับใช้ Encryption

2 Session-based vs JWT แตกต่างกันอย่างไร

Session-based: server สร้าง session id เก็บใน database/memory แล้วส่ง id ผ่าน cookie ให้ client ทุก request client ส่ง id กลับมา server ตรวจกับ store

  • ข้อดี: เพิกถอน session ได้ทันที, ข้อมูลผู้ใช้อยู่ฝั่ง server ปลอดภัยกว่า
  • ข้อเสีย: ต้องมี state ที่ server, scale แนวนอนต้องใช้ shared store (Redis)

JWT: server เซ็น token ที่บรรจุข้อมูลผู้ใช้แล้วส่งให้ client เก็บ client แนบ token มากับทุก request server แค่ verify signature

  • ข้อดี: Stateless, scale ง่าย, ใช้ได้ดีกับ microservices/mobile
  • ข้อเสีย: เพิกถอน token ก่อนหมดอายุยาก, ขนาด token ใหญ่กว่า cookie

เมื่อไหร่ใช้แบบไหน: Web app ทั่วไปที่ต้อง logout ทันทีและคุมจำนวน session ใช้ Session-based; ระบบ microservice/mobile/SPA ที่ต้องการ stateless ใช้ JWT

3 HttpOnly Cookie สำคัญอย่างไร

HttpOnly Cookie คือ cookie ที่ JavaScript ฝั่ง client อ่านไม่ได้ (เข้าได้แค่ผ่าน HTTP request เท่านั้น)

หากเก็บ session id หรือ token ใน localStorage หรือ cookie ปกติ ผู้โจมตีที่ทำ XSS สำเร็จจะสามารถอ่านและขโมยไปสวมสิทธิ์ผู้ใช้ได้ทันที

การใช้ HttpOnly ช่วยป้องกัน XSS ไม่ให้ขโมย token ไปได้ และควรใช้คู่กับ Secure (ส่งผ่าน HTTPS เท่านั้น) และ SameSite=Lax/Strict (ป้องกัน CSRF)

4 SQL Injection คืออะไร และทำไม ORM ถึงปลอดภัยกว่า

SQL Injection คือการโจมตีที่ผู้ใช้แอบแทรกคำสั่ง SQL ผ่าน input เช่น username ปกติคือ admin แต่ผู้โจมตีพิมพ์ admin' OR '1'='1 ถ้าโค้ดต่อ string แบบ "SELECT * FROM users WHERE name='" + input + "'" SQL ที่ได้จะกลายเป็นเงื่อนไขที่จริงเสมอ

ORM (Drizzle, Prisma) ปลอดภัยกว่า เพราะใช้ Parameterized Query / Prepared Statement โดยอัตโนมัติ ค่าที่ส่งเข้าไปจะถูกมองเป็น "ข้อมูล" ไม่ใช่ "คำสั่ง" ฐานข้อมูลจะ escape ให้เอง

นอกจากนี้ ORM ยังมี Type-safety ช่วยให้ TypeScript จับ error ได้ตั้งแต่ตอน compile

5 CORS คืออะไรและเมื่อไหร่ต้องสนใจ

CORS (Cross-Origin Resource Sharing) คือกลไกของ browser ที่ป้องกัน script จาก origin หนึ่งไปเรียก resource ที่ origin อื่นโดยอัตโนมัติ (Same-Origin Policy)

Origin ประกอบด้วย scheme + host + port เช่น http://localhost:3000 กับ http://localhost:5000 ถือว่าคนละ origin

เมื่อไหร่ที่ต้องสนใจ:

  • Frontend และ Backend อยู่คนละ domain/port (เช่น React อยู่ :3000 API อยู่ :8000)
  • Mobile/SPA เรียก API ข้าม domain
  • ต้องการให้ส่ง cookie ข้าม origin (ต้องตั้ง Access-Control-Allow-Credentials: true และระบุ origin ชัดเจน ห้ามใช้ *)

ใน Next.js สามารถตั้งใน next.config.ts หรือใน Route Handler โดยเซ็ต header Access-Control-Allow-Origin

6 REST Conventions ที่ดีเป็นอย่างไร

การออกแบบ URL: ใช้คำนามพหูพจน์ ไม่ใช้ verb ใน URL

  • GET /products - ดึงรายการสินค้าทั้งหมด
  • GET /products/:id - ดึงสินค้าตาม id
  • POST /products - สร้างสินค้าใหม่
  • PUT /products/:id - แทนที่ข้อมูลทั้งก้อน
  • PATCH /products/:id - แก้บางฟิลด์
  • DELETE /products/:id - ลบสินค้า

HTTP Status Codes ที่ใช้บ่อย:

  • 200 OK - สำเร็จทั่วไป (GET, PUT, PATCH)
  • 201 Created - สร้างสำเร็จ (POST)
  • 204 No Content - สำเร็จและไม่มี body (DELETE)
  • 400 Bad Request - input ไม่ถูกต้อง / validation fail
  • 401 Unauthorized - ยังไม่ login
  • 403 Forbidden - login แล้วแต่ไม่มีสิทธิ์
  • 404 Not Found - ไม่พบ resource
  • 409 Conflict - ข้อมูลซ้ำ เช่น email ถูกใช้แล้ว
  • 500 Internal Server Error - error ฝั่ง server

ดาวน์โหลดโค้ดที่ทำครั้งที่แล้ว

ดาวน์โหลดไฟล์ทั้งหมดเป็น zip เดียว แล้วแตกไฟล์เพื่อเริ่มทำต่อ

ZIP
Code.zip
ซอร์สโค้ดของงานก่อนหน้าทั้งหมด (Next.js + Drizzle ORM project)
ดาวน์โหลด ⬇

คำสั่งสำหรับเริ่มต้น

หลังจากแตกไฟล์ Code.zip แล้ว ให้รันคำสั่งต่อไปนี้ตามลำดับใน terminal

1 ติดตั้ง dependencies
npm install

ติดตั้ง package ทั้งหมดที่อยู่ใน package.json

2 สร้าง migration จาก schema
npx drizzle-kit generate

สร้างไฟล์ SQL migration จาก Drizzle schema

3 รัน migration ลง database
npx drizzle-kit migrate

execute migration files ที่ generate ไว้ ลงในฐานข้อมูลจริง

Part 2 — ข้อกำหนดของระบบ

หลังตอบ Part 1 และเตรียมโปรเจกต์เรียบร้อยแล้ว ให้พัฒนาระบบตามข้อกำหนดต่อไปนี้

1

ระบบ Authentication & Authorization

  • Custom Session-based Auth: สร้างระบบ Login และ Logout โดยใช้ Session (เก็บบันทึก Session ลงใน Database)
  • ห้ามใช้ Library สำเร็จรูป: ห้ามใช้ Library สำหรับจัดการ Auth (เช่น NextAuth) ให้เขียน Logic การเข้าสู่ระบบด้วยตัวเอง
  • การจัดการรหัสผ่าน: อนุญาตให้ใช้ bcryptjs ในการทำ Hashing Password เท่านั้น
    npm install bcryptjs
    npm install -D @types/bcryptjs
  • Route Protection: ใช้ไฟล์ middleware.ts ของ Next.js ในการป้องกัน Route หากผู้ใช้งานยังไม่ได้ Login ให้ทำการ Redirect กลับไปที่หน้า /login
  • Role-based Permissions: เพิ่มฟิลด์ role ในตาราง Users โดยมี 2 ระดับคือ 'admin' และ 'user'
    • ผู้ใช้งานสามารถเรียกดูรายการสินค้า (get products) ที่สร้างโดยตัวเองได้
    • หากเป็น admin จะมีสิทธิ์ลบข้อมูลสินค้าของผู้ใช้งานคนอื่นได้
2

การจัดการ API (Products API)

แก้ไขและปรับปรุง API จากงานเดิมให้สมบูรณ์ตามหลัก RESTful ดังนี้:

api/products/route.ts
  • GET List รายการสินค้า
  • POST Create สร้างสินค้าใหม่
api/products/[id]/route.ts
  • GET ดึงข้อมูลสินค้าตาม ID
  • PUT/PATCH Update แก้ไขข้อมูล
  • DELETE ลบข้อมูลสินค้า
3

การตรวจสอบความถูกต้อง (Data Validations)

ต้องมีการทำ Validation ตรวจสอบข้อมูลก่อนนำไปใช้งานเสมอ ทั้งในส่วนของ Auth (เช่น รูปแบบอีเมล, ความยาวรหัสผ่าน) และ Products (เช่น ชื่อสินค้าต้องไม่ว่างเปล่า, ราคาต้องเป็นตัวเลข)

4

การทดสอบ (Testing)

ใช้โปรแกรม Postman (หรือ API Client อื่น ๆ) ในการยิงทดสอบ API ทุก Endpoint ว่าสามารถทำงานได้ถูกต้องตาม Method และคืนค่า Status Code กลับมาได้อย่างเหมาะสม

5

การส่งงาน (Submission)

เมื่อพัฒนาและทดสอบเสร็จเรียบร้อย ให้อัปโหลด Source Code ขึ้น Git (เช่น GitHub) แล้วส่งผลงานโดยการแปะ ลิงก์ Repository ให้ผู้ตรวจ