947 lines
30 KiB
Markdown
947 lines
30 KiB
Markdown
# Prompt: แก้ไข Auth.js ClientFetchError และเพิ่มระบบ Session Inactivity Timeout 5 นาที
|
|
|
|
## บทบาทของคุณ
|
|
|
|
คุณคือ Senior Full-Stack Developer ที่มีความเชี่ยวชาญด้าน:
|
|
|
|
- Next.js 16 App Router
|
|
- React
|
|
- TypeScript
|
|
- Auth.js / NextAuth
|
|
- Middleware
|
|
- Session Management
|
|
- Security และ Authentication Flow
|
|
- TanStack Query หรือระบบ Client State ที่มีอยู่ในโครงการ
|
|
- Next.js Turbopack
|
|
|
|
ให้ตรวจสอบโครงสร้างและโค้ดเดิมของโครงการก่อนดำเนินการแก้ไข โดยต้องปรับปรุงจากโครงสร้างที่มีอยู่จริง ห้ามสร้างระบบ Authentication ซ้ำซ้อนโดยไม่จำเป็น
|
|
|
|
---
|
|
|
|
# ปัญหาที่ต้องแก้ไข
|
|
|
|
ระบบพบ Error ฝั่ง Client ดังนี้:
|
|
|
|
```text
|
|
Error Type:
|
|
Console ClientFetchError
|
|
|
|
Error Message:
|
|
Unexpected token '<', "<!DOCTYPE "... is not valid JSON.
|
|
|
|
Read more at:
|
|
https://errors.authjs.dev#autherror
|
|
|
|
Next.js version:
|
|
16.2.6 (Turbopack)
|
|
```
|
|
|
|
Error นี้บ่งชี้ว่า Client ของ Auth.js คาดว่าจะได้รับ JSON แต่ Endpoint เช่น:
|
|
|
|
```text
|
|
/api/auth/session
|
|
```
|
|
|
|
กลับส่ง HTML Response เช่น:
|
|
|
|
```html
|
|
<!DOCTYPE html>
|
|
```
|
|
|
|
ซึ่งอาจเกิดจาก:
|
|
|
|
- Auth.js Route ไม่ทำงานหรืออยู่ผิดตำแหน่ง
|
|
- `/api/auth/session` ตอบกลับเป็น 404 หรือ 500
|
|
- Middleware Redirect `/api/auth/*` ไปหน้าล็อกอิน
|
|
- Auth.js Configuration Error
|
|
- Database หรือ Adapter Error
|
|
- Environment Variable ไม่ครบหรือไม่ถูกต้อง
|
|
- Custom Error Handler ส่ง HTML แทน JSON
|
|
- Reverse Proxy หรือ Application Redirect ทำให้ Auth API ถูกเปลี่ยนปลายทาง
|
|
- Client เรียก `getSession()` หรือ `useSession()` ขณะที่ Auth Route ล้มเหลว
|
|
- SessionProvider ถูกตั้งค่าผิดตำแหน่ง
|
|
- Error Boundary หรือ Route Handler จัดการ Error ไม่ถูกต้อง
|
|
|
|
---
|
|
|
|
# เป้าหมายหลัก
|
|
|
|
ดำเนินการให้ครบทั้ง 2 ส่วนดังนี้:
|
|
|
|
1. ตรวจสอบและแก้ไข Auth.js `ClientFetchError`
|
|
2. เพิ่มระบบ Session Inactivity Timeout เมื่อผู้ใช้งานไม่มีการเคลื่อนไหวต่อเนื่อง 5 นาที
|
|
|
|
---
|
|
|
|
# ส่วนที่ 1: ตรวจสอบและแก้ไข Auth.js ClientFetchError
|
|
|
|
## 1. ตรวจสอบโครงสร้าง Auth.js ปัจจุบัน
|
|
|
|
ตรวจสอบไฟล์ที่เกี่ยวข้องทั้งหมด เช่น:
|
|
|
|
```text
|
|
auth.ts
|
|
src/auth.ts
|
|
app/api/auth/[...nextauth]/route.ts
|
|
src/app/api/auth/[...nextauth]/route.ts
|
|
middleware.ts
|
|
src/middleware.ts
|
|
proxy.ts
|
|
src/proxy.ts
|
|
providers.tsx
|
|
session-provider.tsx
|
|
layout.tsx
|
|
.env
|
|
.env.local
|
|
next.config.ts
|
|
```
|
|
|
|
รวมถึงไฟล์ Authentication, Authorization และ Database Adapter ที่เกี่ยวข้อง
|
|
|
|
ห้ามสมมติชื่อไฟล์หรือโครงสร้าง ให้ค้นหาจากโครงการจริงก่อน
|
|
|
|
---
|
|
|
|
## 2. ตรวจสอบ Auth Route
|
|
|
|
ตรวจสอบว่า Auth.js Route อยู่ในตำแหน่งที่ถูกต้องสำหรับ App Router เช่น:
|
|
|
|
```text
|
|
src/app/api/auth/[...nextauth]/route.ts
|
|
```
|
|
|
|
และ Export Handler ถูกต้อง เช่น:
|
|
|
|
```ts
|
|
import { handlers } from "@/auth";
|
|
|
|
export const { GET, POST } = handlers;
|
|
```
|
|
|
|
ตรวจสอบเพิ่มเติมว่า:
|
|
|
|
- Import path ถูกต้อง
|
|
- `handlers` ถูก Export จาก Auth configuration จริง
|
|
- ไม่มี Circular Dependency
|
|
- ไม่มี Route อื่นชนกับ `/api/auth/[...nextauth]`
|
|
- ไม่มี Rewrite หรือ Redirect ที่กระทบ Auth Route
|
|
|
|
---
|
|
|
|
## 3. ตรวจสอบ Auth.js Configuration
|
|
|
|
ตรวจสอบไฟล์ Auth configuration ว่ามีรูปแบบถูกต้อง เช่น:
|
|
|
|
```ts
|
|
import NextAuth from "next-auth";
|
|
|
|
export const { handlers, auth, signIn, signOut } = NextAuth({
|
|
providers: [],
|
|
});
|
|
```
|
|
|
|
ตรวจสอบ:
|
|
|
|
- Providers
|
|
- Credentials Provider
|
|
- Adapter
|
|
- Session Strategy
|
|
- JWT Callback
|
|
- Session Callback
|
|
- Authorized Callback
|
|
- Sign-in Page
|
|
- Error Page
|
|
- Environment Variables
|
|
- Database Connection
|
|
- Cookie Configuration
|
|
- Trust Host Configuration
|
|
- Base Path หากมีการตั้งค่า
|
|
|
|
หากมี Custom Adapter หรือ LDAP/Active Directory ให้ตรวจสอบ Error Handling ของส่วนนั้นด้วย
|
|
|
|
---
|
|
|
|
## 4. ตรวจสอบ Endpoint `/api/auth/session`
|
|
|
|
ทดสอบ Endpoint นี้โดยตรง:
|
|
|
|
```text
|
|
GET /api/auth/session
|
|
```
|
|
|
|
ผลลัพธ์ที่ถูกต้องต้องเป็น JSON และมี `Content-Type` เป็น:
|
|
|
|
```text
|
|
application/json
|
|
```
|
|
|
|
ตัวอย่างผลลัพธ์เมื่อยังไม่ได้เข้าสู่ระบบ:
|
|
|
|
```json
|
|
{}
|
|
```
|
|
|
|
หรือ Response ตามมาตรฐานของ Auth.js
|
|
|
|
ต้องไม่ตอบกลับเป็น:
|
|
|
|
- HTML
|
|
- หน้า Login
|
|
- หน้า 404
|
|
- หน้า Error ของ Next.js
|
|
- Redirect ไปหน้าอื่น
|
|
- Reverse Proxy Error Page
|
|
|
|
ให้ตรวจสอบ HTTP Status เช่น:
|
|
|
|
```text
|
|
200
|
|
302
|
|
307
|
|
401
|
|
404
|
|
500
|
|
```
|
|
|
|
และหาสาเหตุจาก Status ที่พบจริง
|
|
|
|
---
|
|
|
|
## 5. ตรวจสอบ Middleware หรือ Proxy
|
|
|
|
ตรวจสอบว่า Middleware หรือ Proxy ไม่ได้ดัก Route ต่อไปนี้:
|
|
|
|
```text
|
|
/api/auth
|
|
/api/auth/*
|
|
/_next/*
|
|
/favicon.ico
|
|
```
|
|
|
|
Auth.js API Route ต้องไม่ถูก Redirect ไปหน้าล็อกอิน
|
|
|
|
ปรับ Matcher ให้ยกเว้น Auth API และ Static Assets อย่างเหมาะสม เช่นแนวทาง:
|
|
|
|
```ts
|
|
export const config = {
|
|
matcher: ["/((?!api/auth|_next/static|_next/image|favicon.ico).*)"],
|
|
};
|
|
```
|
|
|
|
แต่ต้องปรับให้เข้ากับโครงสร้างจริงของโครงการ และต้องไม่ทำให้ Route Protection เดิมเสียหาย
|
|
|
|
หากโครงการใช้ `proxy.ts` ตามโครงสร้างของ Next.js รุ่นปัจจุบัน ให้ตรวจสอบไฟล์นั้นด้วย ไม่จำกัดเฉพาะ `middleware.ts`
|
|
|
|
---
|
|
|
|
## 6. ตรวจสอบ Environment Variables
|
|
|
|
ตรวจสอบ Environment Variables ที่เกี่ยวข้อง เช่น:
|
|
|
|
```text
|
|
AUTH_SECRET
|
|
AUTH_URL
|
|
NEXTAUTH_SECRET
|
|
NEXTAUTH_URL
|
|
DATABASE_URL
|
|
```
|
|
|
|
รวมถึง Environment Variables ของ:
|
|
|
|
- LDAP
|
|
- Active Directory
|
|
- OAuth Provider
|
|
- Database Adapter
|
|
- Reverse Proxy
|
|
- Internal API
|
|
|
|
ให้ใช้ชื่อตัวแปรตาม Version และโครงสร้าง Auth.js ที่โครงการใช้งานจริง
|
|
|
|
ห้ามเปิดเผย Secret ใน Log หรือ Commit
|
|
|
|
หาก Environment Variable ที่จำเป็นขาด ให้เพิ่มตัวอย่างใน:
|
|
|
|
```text
|
|
.env.example
|
|
```
|
|
|
|
โดยใช้ Placeholder เท่านั้น
|
|
|
|
---
|
|
|
|
## 7. ตรวจสอบ Server Error ที่แท้จริง
|
|
|
|
ตรวจสอบ Server Log และ Terminal Log ขณะที่เรียก:
|
|
|
|
```text
|
|
/api/auth/session
|
|
```
|
|
|
|
ค้นหา Root Cause เช่น:
|
|
|
|
- Database Connection Error
|
|
- Prisma Initialization Error
|
|
- LDAP Connection Error
|
|
- Provider Configuration Error
|
|
- Invalid Secret
|
|
- Callback Error
|
|
- JWT Decryption Error
|
|
- Cookie Parsing Error
|
|
- Runtime Compatibility Error
|
|
- Edge Runtime ไม่รองรับ Library บางตัว
|
|
- Node Runtime Configuration Error
|
|
|
|
ห้ามแก้ด้วยการซ่อน Error ฝั่ง Client เพียงอย่างเดียว ต้องแก้ Root Cause ที่ทำให้ Endpoint ส่ง HTML
|
|
|
|
---
|
|
|
|
## 8. ปรับปรุง Error Handling
|
|
|
|
ปรับปรุง Error Handling เพื่อให้:
|
|
|
|
- Auth API ไม่ส่ง HTML Response โดยไม่จำเป็น
|
|
- Client ไม่เกิด Unhandled Promise Rejection
|
|
- ไม่แสดง Stack Trace หรือข้อมูล Sensitive แก่ผู้ใช้งาน
|
|
- Server Log มีข้อมูลเพียงพอสำหรับ Debug
|
|
- Production แสดงข้อความที่เหมาะสม
|
|
- Development ยังสามารถตรวจสอบ Root Cause ได้
|
|
|
|
หาก `useSession()`, `getSession()`, `SessionProvider` หรือ Custom API Client มี Error Handling ไม่ครบ ให้ปรับปรุงด้วย
|
|
|
|
ห้ามใช้วิธีแก้แบบ:
|
|
|
|
```ts
|
|
try {
|
|
// ...
|
|
} catch {
|
|
return null;
|
|
}
|
|
```
|
|
|
|
หากทำให้ Root Cause ถูกซ่อนโดยไม่มี Logging ที่เหมาะสม
|
|
|
|
---
|
|
|
|
# ส่วนที่ 2: เพิ่มระบบ Session Inactivity Timeout 5 นาที
|
|
|
|
## ความต้องการ
|
|
|
|
เมื่อผู้ใช้งานเข้าสู่ระบบแล้ว หากไม่มีการเคลื่อนไหวหรือไม่มี Interaction กับระบบต่อเนื่องเป็นเวลา:
|
|
|
|
```text
|
|
5 นาที
|
|
```
|
|
|
|
ให้ระบบดำเนินการดังนี้:
|
|
|
|
1. แสดงข้อความแจ้งผู้ใช้งานว่า:
|
|
|
|
```text
|
|
คุณไม่ได้ใช้งานระบบเป็นเวลานาน เซสชันของคุณหมดอายุแล้ว กรุณาเข้าสู่ระบบใหม่
|
|
```
|
|
|
|
2. ทำการ Sign out จาก Auth.js อย่างถูกต้อง
|
|
3. ล้าง Client State หรือข้อมูล Session ที่เกี่ยวข้อง
|
|
4. Redirect กลับไปหน้าล็อกอิน
|
|
5. ผู้ใช้งานต้องเข้าสู่ระบบใหม่ก่อนใช้งานระบบต่อ
|
|
6. ห้ามเกิด Redirect Loop
|
|
7. ห้ามกระทบผู้ใช้งานที่ยังมีการเคลื่อนไหวอยู่
|
|
|
|
---
|
|
|
|
## 1. นิยาม Activity ของผู้ใช้งาน
|
|
|
|
ให้ถือว่า Event ต่อไปนี้เป็น Activity:
|
|
|
|
```text
|
|
mousedown
|
|
mousemove
|
|
keydown
|
|
scroll
|
|
touchstart
|
|
click
|
|
focus
|
|
```
|
|
|
|
สามารถเลือกใช้เฉพาะ Event ที่เหมาะสมเพื่อไม่ให้เกิด Performance Issue
|
|
|
|
ต้องใช้ Event แบบ Throttle หรือ Debounce เพื่อไม่ให้ Reset Timer ถี่เกินไป โดยเฉพาะ:
|
|
|
|
```text
|
|
mousemove
|
|
scroll
|
|
```
|
|
|
|
---
|
|
|
|
## 2. เริ่มตรวจจับเฉพาะผู้ที่เข้าสู่ระบบแล้ว
|
|
|
|
ระบบ Inactivity Timeout ต้องทำงานเฉพาะเมื่อ:
|
|
|
|
```ts
|
|
status === "authenticated";
|
|
```
|
|
|
|
ห้ามเริ่ม Timer ในกรณี:
|
|
|
|
```ts
|
|
status === "loading";
|
|
status === "unauthenticated";
|
|
```
|
|
|
|
เมื่อผู้ใช้งาน Logout แล้ว ต้อง Cleanup:
|
|
|
|
- Timer
|
|
- Event Listener
|
|
- Storage Listener
|
|
- Broadcast Channel
|
|
- Pending Callback
|
|
|
|
ทั้งหมดอย่างถูกต้อง
|
|
|
|
---
|
|
|
|
## 3. ระยะเวลา Timeout
|
|
|
|
กำหนดค่ากลาง เช่น:
|
|
|
|
```ts
|
|
const INACTIVITY_TIMEOUT_MS = 5 * 60 * 1000;
|
|
```
|
|
|
|
ควรจัดเก็บไว้ใน Configuration หรือ Constant กลาง เพื่อให้เปลี่ยนภายหลังได้ง่าย
|
|
|
|
ห้ามกระจายค่า `300000` ไว้หลายจุดในระบบ
|
|
|
|
---
|
|
|
|
## 4. รูปแบบการแจ้งเตือน
|
|
|
|
เมื่อครบ 5 นาที ให้แสดง Dialog, AlertDialog, Modal หรือ Toast ตาม Component มาตรฐานของโครงการ
|
|
|
|
แนะนำให้ใช้:
|
|
|
|
```text
|
|
AlertDialog
|
|
```
|
|
|
|
ข้อความ:
|
|
|
|
```text
|
|
เซสชันหมดอายุ
|
|
```
|
|
|
|
รายละเอียด:
|
|
|
|
```text
|
|
คุณไม่ได้ใช้งานระบบเป็นเวลานาน เซสชันของคุณหมดอายุแล้ว กรุณาเข้าสู่ระบบใหม่
|
|
```
|
|
|
|
ปุ่ม:
|
|
|
|
```text
|
|
เข้าสู่ระบบใหม่
|
|
```
|
|
|
|
เมื่อผู้ใช้งานกดปุ่ม ให้ Redirect ไปหน้าล็อกอิน
|
|
|
|
อย่างไรก็ตาม เพื่อความปลอดภัย ระบบต้อง Sign out และถือว่า Session หมดอายุทันทีเมื่อครบเวลา ไม่ควรรอให้ผู้ใช้งานกดปุ่มก่อนจึงค่อย Sign out
|
|
|
|
หากใช้ Toast ให้ตั้งระยะเวลาที่ผู้ใช้งานสามารถอ่านข้อความได้อย่างเหมาะสมก่อน Redirect
|
|
|
|
ห้ามใช้ Native Browser Alert หากโครงการมี UI Component มาตรฐานอยู่แล้ว
|
|
|
|
---
|
|
|
|
## 5. ลำดับการทำงานเมื่อหมดเวลา
|
|
|
|
ลำดับที่ต้องการ:
|
|
|
|
```text
|
|
ครบเวลาไม่มี Activity
|
|
↓
|
|
ป้องกันการทำงานซ้ำด้วย Flag
|
|
↓
|
|
หยุด Timer และถอด Event Listener
|
|
↓
|
|
แสดงข้อความแจ้ง Session หมดอายุ
|
|
↓
|
|
ล้างข้อมูล Client State ที่มีความ Sensitive
|
|
↓
|
|
เรียก signOut ของ Auth.js
|
|
↓
|
|
Redirect ไปหน้า Login
|
|
```
|
|
|
|
ตัวอย่างแนวทาง:
|
|
|
|
```ts
|
|
await signOut({
|
|
redirect: false,
|
|
});
|
|
|
|
router.replace("/login?reason=inactivity");
|
|
router.refresh();
|
|
```
|
|
|
|
ให้ปรับตาม Auth.js API และโครงสร้างจริงของโครงการ
|
|
|
|
หากจำเป็นต้องแสดงข้อความหลัง Redirect ให้ส่ง Query Parameter เช่น:
|
|
|
|
```text
|
|
/login?reason=inactivity
|
|
```
|
|
|
|
จากนั้นหน้า Login แสดงข้อความ:
|
|
|
|
```text
|
|
คุณไม่ได้ใช้งานระบบเป็นเวลานาน เซสชันของคุณหมดอายุแล้ว กรุณาเข้าสู่ระบบใหม่
|
|
```
|
|
|
|
ต้องลบหรือ Replace URL อย่างเหมาะสมหลังแสดงข้อความ เพื่อไม่ให้ข้อความแสดงซ้ำเมื่อ Refresh โดยไม่จำเป็น
|
|
|
|
---
|
|
|
|
## 6. รองรับหลาย Tab
|
|
|
|
ระบบควรรองรับกรณีเปิดหลาย Browser Tab
|
|
|
|
เมื่อผู้ใช้งานมี Activity ใน Tab หนึ่ง ควร Sync `lastActivity` ให้ Tab อื่นรับรู้ เพื่อไม่ให้ Tab อื่น Logout ผู้ใช้งานผิดพลาด
|
|
|
|
สามารถใช้:
|
|
|
|
```text
|
|
localStorage
|
|
storage event
|
|
BroadcastChannel
|
|
```
|
|
|
|
แนวทางที่แนะนำ:
|
|
|
|
```text
|
|
auth:last-activity
|
|
auth:session-expired
|
|
```
|
|
|
|
ข้อกำหนด:
|
|
|
|
- Activity จาก Tab หนึ่งต้องอัปเดตเวลาให้ Tab อื่น
|
|
- เมื่อ Session หมดอายุใน Tab หนึ่ง Tab อื่นต้อง Logout ตาม
|
|
- ป้องกันหลาย Tab เรียก `signOut()` พร้อมกันจำนวนมาก
|
|
- Cleanup Channel และ Listener เมื่อ Component Unmount
|
|
- ต้องตรวจสอบการทำงานใน Browser ที่ไม่รองรับ `BroadcastChannel`
|
|
|
|
---
|
|
|
|
## 7. ห้ามใช้เฉพาะ Client Timer เป็น Security Control
|
|
|
|
Client-side inactivity timer เป็นส่วนของ UX เท่านั้น
|
|
|
|
ต้องตรวจสอบ Session Configuration ฝั่ง Server ร่วมด้วย เช่น:
|
|
|
|
- JWT expiration
|
|
- Session maxAge
|
|
- Cookie expiration
|
|
- Server-side authorization
|
|
- Permission validation ใน Protected Route
|
|
- API Route ต้องตรวจ Session ทุกครั้ง
|
|
|
|
ห้ามถือว่าผู้ใช้หมดสิทธิ์เพียงเพราะ Client Redirect แล้วเท่านั้น
|
|
|
|
อย่างไรก็ตาม ระยะเวลาหมดอายุฝั่ง Server ไม่จำเป็นต้องเท่ากับ Inactivity Timeout 5 นาที หากระบบต้องรองรับ Sliding Session แต่ต้องอธิบายความแตกต่างไว้ใน Implementation Report
|
|
|
|
---
|
|
|
|
## 8. ระวังการสูญหายของข้อมูลใน Form
|
|
|
|
ตรวจสอบว่าหน้าใดมี Form ที่ผู้ใช้งานอาจกำลังกรอกข้อมูล
|
|
|
|
เมื่อ Session หมดอายุ:
|
|
|
|
- ต้องไม่พยายามบันทึกข้อมูลหลังหมด Session
|
|
- ต้องไม่เกิด API Request ด้วย Session ที่หมดอายุ
|
|
- ต้องไม่เก็บข้อมูล Sensitive ไว้ใน Local Storage โดยไม่จำเป็น
|
|
- สามารถแจ้งข้อความว่าข้อมูลที่ยังไม่ได้บันทึกอาจสูญหายได้ หากเหมาะสม
|
|
|
|
ไม่ต้องเพิ่มระบบ Auto Save เว้นแต่โครงการมีอยู่แล้ว
|
|
|
|
---
|
|
|
|
# สถาปัตยกรรมที่แนะนำ
|
|
|
|
สร้าง Component หรือ Hook กลาง เช่น:
|
|
|
|
```text
|
|
src/components/auth/session-inactivity-guard.tsx
|
|
```
|
|
|
|
หรือ:
|
|
|
|
```text
|
|
src/hooks/use-session-inactivity.ts
|
|
```
|
|
|
|
แล้วนำไปติดตั้งในตำแหน่งที่ครอบคลุมเฉพาะ Protected Area เช่น:
|
|
|
|
```text
|
|
src/app/dashboard/layout.tsx
|
|
```
|
|
|
|
หรือ Protected Layout ที่มีอยู่จริง
|
|
|
|
ไม่ควรติดตั้งใน Root Layout หากทำให้หน้า Login เริ่มจับเวลาโดยไม่จำเป็น
|
|
|
|
ตัวอย่างโครงสร้าง:
|
|
|
|
```text
|
|
Protected Layout
|
|
├── SessionProvider
|
|
├── SessionInactivityGuard
|
|
└── Protected Page Content
|
|
```
|
|
|
|
ให้ใช้ Provider และ Layout เดิมของโครงการ หากมีอยู่แล้ว
|
|
|
|
---
|
|
|
|
# ข้อกำหนดด้าน UX
|
|
|
|
## ข้อความภาษาไทย
|
|
|
|
หัวข้อ:
|
|
|
|
```text
|
|
เซสชันหมดอายุ
|
|
```
|
|
|
|
รายละเอียด:
|
|
|
|
```text
|
|
คุณไม่ได้ใช้งานระบบเป็นเวลานาน เซสชันของคุณหมดอายุแล้ว กรุณาเข้าสู่ระบบใหม่
|
|
```
|
|
|
|
ปุ่ม:
|
|
|
|
```text
|
|
เข้าสู่ระบบใหม่
|
|
```
|
|
|
|
กรณี Redirect ไปหน้า Login โดยตรง ให้หน้า Login แสดงข้อความ:
|
|
|
|
```text
|
|
คุณไม่ได้ใช้งานระบบเป็นเวลานาน กรุณาเข้าสู่ระบบใหม่
|
|
```
|
|
|
|
---
|
|
|
|
# ข้อกำหนดด้านความปลอดภัย
|
|
|
|
- ห้าม Log Token
|
|
- ห้าม Log Cookie
|
|
- ห้าม Log Password
|
|
- ห้าม Log LDAP Credential
|
|
- ห้ามเปิดเผย Environment Secret
|
|
- ห้ามเก็บ Access Token ใน Local Storage หากระบบเดิมไม่ได้ออกแบบเช่นนั้น
|
|
- API และ Server Action ต้องตรวจ Session ฝั่ง Server
|
|
- Protected Route ต้องไม่พึ่ง Client Guard เพียงอย่างเดียว
|
|
- ป้องกัน Open Redirect
|
|
- Redirect URL ต้องเป็น Internal Path ที่กำหนดไว้
|
|
- ป้องกันการเรียก Logout ซ้ำ
|
|
- ป้องกัน Redirect Loop ระหว่าง Login และ Protected Route
|
|
|
|
---
|
|
|
|
# Test Cases ที่ต้องตรวจสอบ
|
|
|
|
## Auth.js Error
|
|
|
|
### TC-AUTH-001
|
|
|
|
เปิด:
|
|
|
|
```text
|
|
/api/auth/session
|
|
```
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- HTTP Status ถูกต้อง
|
|
- Response เป็น JSON
|
|
- `Content-Type` เป็น JSON
|
|
- ไม่มี HTML Response
|
|
|
|
### TC-AUTH-002
|
|
|
|
เปิดหน้า Protected Route ขณะยังไม่เข้าสู่ระบบ
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- Redirect ไปหน้า Login อย่างถูกต้อง
|
|
- `/api/auth/session` ไม่ถูก Middleware Redirect
|
|
- ไม่เกิด `Unexpected token '<'`
|
|
|
|
### TC-AUTH-003
|
|
|
|
เข้าสู่ระบบสำเร็จ
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- `useSession()` ได้สถานะ `authenticated`
|
|
- ไม่มี `ClientFetchError`
|
|
- Session โหลดได้ตามปกติ
|
|
|
|
### TC-AUTH-004
|
|
|
|
Database หรือ LDAP ไม่พร้อมใช้งาน
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- Server มี Error Log ที่เหมาะสม
|
|
- Client ไม่เกิด Unhandled Error
|
|
- ผู้ใช้งานได้รับข้อความที่เหมาะสม
|
|
- ไม่มีข้อมูล Sensitive ถูกเปิดเผย
|
|
|
|
---
|
|
|
|
## Session Inactivity Timeout
|
|
|
|
### TC-IDLE-001
|
|
|
|
เข้าสู่ระบบและไม่มี Activity 5 นาที
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- แสดงข้อความ Session หมดอายุ
|
|
- Sign out สำเร็จ
|
|
- Redirect ไปหน้า Login
|
|
- ต้อง Login ใหม่
|
|
|
|
### TC-IDLE-002
|
|
|
|
มี Activity ก่อนครบ 5 นาที
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- Timer ถูก Reset
|
|
- ผู้ใช้งานไม่ถูก Logout
|
|
|
|
### TC-IDLE-003
|
|
|
|
มี Activity ต่อเนื่อง
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- ระบบไม่ Logout
|
|
- ไม่มี Memory Leak
|
|
- ไม่มี Timer ถูกสร้างซ้ำ
|
|
|
|
### TC-IDLE-004
|
|
|
|
เปิดระบบหลาย Tab และใช้งานอยู่ใน Tab หนึ่ง
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- Activity Sync ไปยัง Tab อื่น
|
|
- Tab อื่นไม่ Logout ผู้ใช้งานผิดพลาด
|
|
|
|
### TC-IDLE-005
|
|
|
|
Session หมดอายุใน Tab หนึ่ง
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- ทุก Tab รับรู้ว่า Session หมดอายุ
|
|
- ทุก Tab กลับหน้า Login
|
|
- ไม่เรียก Sign out ซ้ำอย่างผิดปกติ
|
|
|
|
### TC-IDLE-006
|
|
|
|
Logout ด้วยตนเองก่อนครบเวลา
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- Timer และ Event Listener ถูก Cleanup
|
|
- ไม่แสดงข้อความ Inactivity ภายหลัง
|
|
|
|
### TC-IDLE-007
|
|
|
|
Refresh หน้าใกล้ครบเวลา
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- ระบบอ่าน `lastActivity` ที่เหมาะสม
|
|
- ไม่ Reset Timeout อย่างไม่ถูกต้อง หากไม่มี Activity จริง
|
|
- ไม่ Logout ซ้ำ
|
|
|
|
### TC-IDLE-008
|
|
|
|
อยู่หน้า Login
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- ไม่มี Inactivity Timer ทำงาน
|
|
- ไม่มี Redirect Loop
|
|
- ไม่มีข้อความหมดอายุแสดงซ้ำโดยไม่จำเป็น
|
|
|
|
### TC-IDLE-009
|
|
|
|
ผู้ใช้งานกำลังกรอก Form แต่ไม่มี Mouse หรือ Keyboard Activity เกิน 5 นาที
|
|
|
|
ผลลัพธ์ที่คาดหวัง:
|
|
|
|
- Session หมดอายุตามข้อกำหนด
|
|
- ระบบแจ้งเตือนอย่างชัดเจน
|
|
- ไม่มีการส่ง Form หลัง Session หมดอายุ
|
|
|
|
---
|
|
|
|
# Quality Gate
|
|
|
|
ก่อนจบงานต้องดำเนินการ:
|
|
|
|
```bash
|
|
npm run lint
|
|
npm run typecheck
|
|
npm run build
|
|
```
|
|
|
|
หรือใช้คำสั่งที่มีอยู่จริงใน `package.json`
|
|
|
|
ต้องแก้ไข:
|
|
|
|
- TypeScript Error
|
|
- ESLint Error
|
|
- Build Error
|
|
- Import Error
|
|
- Hydration Error
|
|
- Unhandled Promise Rejection
|
|
- Memory Leak จาก Timer หรือ Event Listener
|
|
|
|
ห้ามปิด Rule หรือใช้:
|
|
|
|
```ts
|
|
any
|
|
@ts-ignore
|
|
eslint-disable
|
|
```
|
|
|
|
โดยไม่มีเหตุผลที่จำเป็นและมีคำอธิบาย
|
|
|
|
---
|
|
|
|
# ข้อจำกัดในการแก้ไข
|
|
|
|
- รักษาโครงสร้างและ Coding Convention เดิม
|
|
- ใช้ Component มาตรฐานที่โครงการมีอยู่แล้ว
|
|
- ไม่สร้าง Auth Provider ซ้ำ
|
|
- ไม่เปลี่ยน Authentication Flow โดยไม่จำเป็น
|
|
- ไม่ลบ Permission หรือ Route Protection เดิม
|
|
- ไม่ Hardcode Domain
|
|
- ไม่ Hardcode Secret
|
|
- ไม่ Hardcode Login URL หลายตำแหน่ง
|
|
- ไม่เปลี่ยน Session Strategy หากไม่มีเหตุผลรองรับ
|
|
- ไม่แก้เฉพาะอาการโดยละเลย Root Cause
|
|
- ห้ามทำให้ `/api/auth/session` ถูก Redirect ไปหน้า Login
|
|
|
|
---
|
|
|
|
# ผลลัพธ์ที่ต้องส่งมอบ
|
|
|
|
หลังดำเนินการเสร็จ ให้จัดทำรายงานสรุป Markdown โดยประกอบด้วย:
|
|
|
|
## 1. Root Cause
|
|
|
|
ระบุสาเหตุจริงของ:
|
|
|
|
```text
|
|
Unexpected token '<', "<!DOCTYPE "... is not valid JSON
|
|
```
|
|
|
|
พร้อมระบุว่า HTML Response มาจาก:
|
|
|
|
- Route ใด
|
|
- HTTP Status ใด
|
|
- Middleware, Server Error หรือ Configuration ส่วนใด
|
|
|
|
## 2. Files Changed
|
|
|
|
ระบุรายการไฟล์ที่:
|
|
|
|
- เพิ่มใหม่
|
|
- แก้ไข
|
|
- ลบ
|
|
|
|
พร้อมสรุปหน้าที่ของแต่ละไฟล์
|
|
|
|
## 3. Auth.js Fix
|
|
|
|
อธิบาย:
|
|
|
|
- สิ่งที่ผิด
|
|
- วิธีแก้
|
|
- เหตุผลที่วิธีใหม่ถูกต้อง
|
|
- ผลทดสอบ `/api/auth/session`
|
|
|
|
## 4. Inactivity Timeout Implementation
|
|
|
|
อธิบาย:
|
|
|
|
- จุดที่ติดตั้ง Guard
|
|
- Event ที่ใช้ตรวจ Activity
|
|
- วิธี Reset Timer
|
|
- วิธี Logout
|
|
- วิธี Redirect
|
|
- วิธีรองรับหลาย Tab
|
|
- วิธี Cleanup
|
|
|
|
## 5. Security Notes
|
|
|
|
อธิบาย:
|
|
|
|
- Client Timeout
|
|
- Server Session Expiration
|
|
- Protected API
|
|
- Cookie และ Token Handling
|
|
- ข้อจำกัดที่ยังเหลืออยู่
|
|
|
|
## 6. Test Results
|
|
|
|
สรุปผล:
|
|
|
|
```text
|
|
Lint
|
|
Typecheck
|
|
Build
|
|
Manual Test
|
|
Auth Session Endpoint Test
|
|
Multi-tab Test
|
|
Inactivity Test
|
|
```
|
|
|
|
## 7. Remaining Risks
|
|
|
|
หากยังมีข้อจำกัดหรือสิ่งที่ต้องดำเนินการต่อ ให้ระบุอย่างตรงไปตรงมา ห้ามรายงานว่าสำเร็จหากยังไม่ได้ทดสอบจริง
|
|
|
|
---
|
|
|
|
# Acceptance Criteria
|
|
|
|
งานถือว่าเสร็จสมบูรณ์เมื่อ:
|
|
|
|
- ไม่เกิด `ClientFetchError`
|
|
- ไม่เกิด `Unexpected token '<'`
|
|
- `/api/auth/session` ตอบกลับเป็น JSON
|
|
- Middleware ไม่ Redirect Auth API
|
|
- ผู้ใช้เข้าสู่ระบบได้ตามปกติ
|
|
- ผู้ใช้ที่ไม่มี Activity ครบ 5 นาทีถูก Sign out
|
|
- มีข้อความแจ้งว่าไม่ได้ใช้งานระบบเป็นเวลานาน
|
|
- Redirect กลับหน้า Login สำเร็จ
|
|
- ต้องเข้าสู่ระบบใหม่
|
|
- Activity ก่อนครบเวลาสามารถ Reset Timer ได้
|
|
- รองรับหลาย Tab
|
|
- ไม่มี Redirect Loop
|
|
- ไม่มี Timer หรือ Event Listener ค้าง
|
|
- Protected API ยังตรวจสอบ Session ฝั่ง Server
|
|
- Lint, Typecheck และ Build ผ่าน
|
|
- มี Implementation Report สรุป Root Cause และการแก้ไข
|