ChiYu Code Journey

安安,我是 ChiYu!

昨天,我們成功地兌現了對使用者的最終承諾,將冰冷的數據轉化為了富有情感的、能啟發洞察的視覺化故事。我們的 App 核心價值已然確立。

但是,我們的 App 現在還像是一個 沒有門鎖的豪宅。雖然內部裝潢精美、功能強大,但任何人都可以隨意進出,這對於一個旨在儲存使用者私密心情與習慣數據的應用來說,是絕對不可接受的。

使用者認證 (Authentication) 流程,是任何嚴肅 Web 應用的基石。它複雜、涉及安全性、且牽一髮而動全身。因此,我們 絕對不能憑感覺去寫!

今天,我們將進行第二個前端的 DDD 循環!我們將扮演一位「資安架構師」,與 Gemini 一同腦力激盪,為這個最關鍵的功能,撰寫一份清晰、專業的**「前端認證流程規格書」**。

Part 1:前端心法:在寫 Code 前,先成為半個資安專家

在我們觸碰任何跟認證相關的程式碼之前,我們必須先在腦中建立起清晰的資安模型。這不僅僅是「使用者體驗」的問題,更是「使用者信任」的基石。

1.1 核心觀念:認證 (Authentication) vs. 授權 (Authorization)

首先,要釐清兩個最常被搞混的概念:

1.2 現代 Web 的通行證:JWT (JSON Web Token)

在現代 Web App 中,我們如何實現無狀態 (Stateless) 的認證呢?答案就是 JWT

你可以把 JWT 想像成一張 蓋了章的「數位通行證」。當你用帳號密碼成功登入後,伺服器會發給你一張 JWT。這張通行證本身包含了一些資訊(例如你是誰、你的權限是什麼),並且經過伺服器的 數位簽章,確保它沒有被偽造。

之後,你每次要向伺服器請求資料時,只需要在請求中附上這張通行證,伺服器看到上面有自己蓋的章,就知道你是合法的使用者,而不需要每次都重新去資料庫查驗你的帳號密碼。

1.3 OAuth 2.0:安全的「授權代理」

你一定用過「透過 Google / Facebook 登入」的功能。這背後,就是 OAuth 2.0 的功勞。

OAuth 2.0 本質上不是一個「認證」協議,而是一個 **「授權 (Authorization)」**框架。它的核心思想是 「安全的代理授權」

比喻來說: 假設你的 App (我們的 MindTrack) 是一個需要你家(Google 帳戶)鑰匙的「清潔服務公司」。

  • 不安全的作法:你直接把你的 Google 帳號密碼告訴 MindTrack。這太危險了!MindTrack 不僅能打掃你的房間(讀取基本資料),還能動用你的存款、看你的私密信件!
  • OAuth 2.0 的作法:你想請 MindTrack 來打掃時,MindTrack 會把你帶到 Google 的「物業管理處」。你在這裡向 Google 確認:「是的,我同意讓 MindTrack 進入我家,但 只授權他打掃客廳(讀取你的基本個人資料),絕對不准進臥室(讀取你的信件)!」

Google 確認後,不會把你的「萬能鑰匙」給 MindTrack,而是會給他一張 有特定權限、有時效性的「臨時通行證」。MindTrack 拿著這張臨時通行證,就可以來幫你打掃客廳了。

雖然我們的 MVP 不會實作 OAuth 2.0,但理解這個觀念,是你邁向專業開發者的重要一步。

Part 2:Vibe Coding 實戰:撰寫我們的「安全白皮書」

好了,理論武裝完畢!讓我們進入 gemini chat 模式,指揮 AI 為我們撰寫這份至關重要的安全規格書。

【魔法詠唱:設計認證流程】

# 角色 (Role)
你是一位頂尖的資安架構師與資深前端工程師,是 Web 安全、JWT (JSON Web Token) 認證機制、前端路由管理與 API 客戶端設計的權威專家。你致力於在確保安全性的前提下,打造無縫、穩固且可擴展的使用者認證體驗。

# 目標 (Objective)
請根據我提供的專案上下文,為我們的 Web App 設計一份專業、完整、且具備高度可執行性的**「前端認證架構藍圖 (Frontend Authentication Architectural Blueprint)」**。這份文件將作為開發團隊實現所有安全相關功能的唯一真理來源。

# 上下文與關鍵資訊 (Context & Key Information)
* **核心需求**: 我們需要為 App 實現使用者故事 #1:「使用者註冊/登入」。(`@docs/USER_STORIES.md`)
* **後端契約**: 我們後端的 `/auth/login``/auth/register` 端點,在成功後會返回一個包含 `accessToken` (JWT) 的 JSON 物件。(`@docs/API_SPEC.yml`)
* **核心挑戰**: 設計一個既安全又具備良好使用者體驗的前端認證系統。

# 產出格式與要求 (Your Task & Output Requirements)
**請生成一份專業的 Markdown 文件,並嚴格遵循以下大綱結構:**

### 1. **核心原則與架構決策**
* **技術選型與權衡 (Tech Choices & Trade-offs)**:
    * **Token 儲存策略**: 明確我們將選擇 `localStorage` 來儲存 JWT Token。 **請深入分析此決策**:闡述其優點(API 簡單、跨分頁共享),並 **詳細列出其主要安全風險(易受 XSS 攻擊)及對應的基礎緩解措施**(例如:內容安全策略 CSP、輸入淨化)。
    * **API 客戶端攔截器 (API Client Interceptor)**: 說明我們將 **必須**建立一個集中的 `fetch` 封裝函式或使用類似 `axios` 的攔截器。其核心職責是:在 **每個**發出的請求中,自動從 `localStorage` 讀取 Token 並將其附加到 `Authorization` 標頭中。

### 2. **前端認證狀態機 (Frontend Auth State Machine)**
* 說明我們將在前端的 `state` 物件中,維護一個完整的認證狀態機,而不僅僅是一個布林值。
* **狀態定義**:
    * `authStatus: 'idle' | 'loading' | 'authenticated' | 'unauthenticated' | 'error'`
    * `user: { id, name, email } | null`
    * `error: string | null`
* **設計理由**: 簡述為何使用狀態機能夠更優雅地處理 UI 變化(例如,在 `loading` 狀態下禁用登入按鈕)。

### 3. **核心流程圖 (Core Flowcharts)**
* 使用 Mermaid.js 的 `graph TD` 語法,為以下三個核心流程,分別繪製包含 **UI 狀態變化**的清晰流程圖:
    * **使用者登入流程**: 需包含「更新狀態為 loading」、「禁用按鈕」、「API 請求」、「成功後儲存 Token」、「更新狀態為 authenticated」、「失敗後更新狀態為 error」等節點。
    * **使用者登出流程**: 需包含「清除 Token」、「清除本地狀態」、「API 請求(可選)」、「重新導向」。
    * **應用程式啟動時的認證檢查流程**: 需包含「檢查本地 Token」、「驗證 Token 有效性(可選)」、「設定初始狀態」。

### 4. **路由與授權:路由守衛 (Routing & Authorization: Route Guards)**
* **概念闡述**: 深入淺出地解釋什麼是「路由守衛」,並使用「每個房間門口的保全」的比喻。
* **職責定義**:
    * **公開路由 (Public Routes)**: 如 `/login`, `/register`,任何人都可以訪問。
    * **私有路由 (Private Routes)**: 如 `/dashboard`, `/settings`,必須在進入前由「路由守衛」檢查 `state.isAuthenticated` (或 Token 的有效性)。
    * **無權限處理**: 若檢查失敗,路由守衛必須立即將使用者**重新導向 (Redirect)** 至登入頁面。

### 5. **錯誤處理與 Token 過期策略**
* **集中處理**: 定義 API 客戶端攔截器的另一項核心職責:**攔截 API 回應**。
* **標準流程**: 當攔截器偵測到後端返回 `401 Unauthorized` 狀態碼時,它必須觸發一個**全域的登出程序**(清除 Token、重設狀態、重新導向到登入頁),而無需每個元件單獨處理。

### 6. **最終產出**
* 將以上所有內容,生成到 `docs/AUTH_FLOW.md` 檔案中。

Part 3:審核 AI 產出的「安全白皮書」

AI 完成操作後,讓我們來仔細品味一下這份由我們共同創作的、專業的「安全設計圖」。

# 前端認證架構藍圖 (Frontend Authentication Architectural Blueprint)

- **文件版本**: 1.0
- **作者**: Gemini (資安架構師 / 資深前端工程師)
- **狀態**: `草案`

---

## 1. 核心原則與架構決策

### 1.1. 技術選型與權衡 (Token 儲存策略)

我們將選擇 `localStorage` 來儲存 JWT (JSON Web Token)。此決策基於以下考量:

-   **優點**:
    -   **API 簡單易用**: `localStorage` 提供直觀的 `setItem()`, `getItem()`, `removeItem()` 方法,易於開發者操作。
    -   **跨分頁共享**: 儲存在 `localStorage` 中的 Token 可以被同源 (same-origin) 的所有瀏覽器分頁共享,方便使用者在多個分頁間保持登入狀態。
    -   **持久化儲存**: Token 會在瀏覽器關閉後依然存在,使用者無需每次開啟瀏覽器都重新登入,提升使用者體驗。

-   **主要安全風險 (XSS 攻擊)**:
    -   `localStorage` 中的數據**容易受到跨站腳本 (XSS) 攻擊**。一旦攻擊者成功在頁面中注入惡意 JavaScript 程式碼,他們就可以直接存取 `localStorage` 中的所有數據,包括 JWT Token。攻擊者獲取 Token 後,即可冒充使用者發送請求,造成會話劫持 (Session Hijacking)。

-   **基礎緩解措施**:
    -   **內容安全策略 (Content Security Policy, CSP)**: 實施嚴格的 CSP,限制頁面可以載入的腳本、樣式和其他資源的來源。這能有效防禦大多數 XSS 攻擊,因為它阻止了惡意腳本的載入和執行。
    -   **輸入淨化 (Input Sanitization)**: 對所有來自使用者或外部來源的輸入數據進行嚴格的驗證、過濾和淨化,防止惡意程式碼(如 `<script>` 標籤)被儲存到資料庫或直接顯示在頁面上。
    -   **輸出編碼 (Output Encoding)**: 在將任何來自使用者或不可信來源的數據渲染到 DOM 之前,對其進行適當的編碼(例如 HTML 實體編碼)。這可以防止瀏覽器將惡意數據解釋為可執行程式碼。
    -   **Token 有效期短**: 設定 JWT 的有效期限盡可能短(例如 15-30 分鐘)。即使 Token 被盜,其生命週期也有限,降低了攻擊的窗口。應搭配 Refresh Token 機制來無感刷新 Token,但 Refresh Token 應儲存在更安全的 `HttpOnly` Cookie 中,這屬於後端和更複雜的前端範疇。
    -   **不儲存敏感資訊**: JWT 的 Payload 應只包含非敏感的公開資訊(如使用者 ID、角色),不應包含密碼、信用卡號等敏感數據。

### 1.2. API 客戶端攔截器 (API Client Interceptor)

我們將在 `api.js` 模組中建立一個集中的 `apiFetch` 封裝函式(已實現)。其核心職責是:在**每個**發出的請求中,自動從 `localStorage` 讀取 Token 並將其附加到 `Authorization: Bearer <token>` 標頭中。這確保了所有需要認證的 API 請求都能自動攜帶 Token,簡化了業務邏輯的開發。

---

## 2. 前端認證狀態機 (Frontend Auth State Machine)

我們將在前端的 `state` 物件中,維護一個完整的認證狀態機,而不僅僅是一個布林值。這使得 UI 能夠更精確地反映認證過程中的不同階段,提供更優質的使用者體驗。

-   **狀態定義**:
    -   `authStatus: 'idle' | 'loading' | 'authenticated' | 'unauthenticated' | 'error'`
        -   `idle`: 應用程式初始狀態,或認證流程未啟動。
        -   `loading`: 正在進行登入、註冊或 Token 驗證等認證相關的非同步操作。
        -   `authenticated`: 使用者已成功登入並通過驗證,具備訪問受保護資源的權限。
        -   `unauthenticated`: 使用者未登入,或其 Token 無效/已過期,無法訪問受保護資源。
        -   `error`: 在認證過程中發生了錯誤(例如網路問題、憑證錯誤)。
    -   `user: { id, name, email } | null`: 儲存已認證使用者的基本資訊。在 `unauthenticated``error` 狀態下為 `null`    -   `error: string | null`: 儲存認證過程中發生的具體錯誤訊息,用於向使用者顯示。

-   **設計理由**:
    -   **精確的 UI 反饋**: 能夠根據 `authStatus` 精確地控制 UI 元素(例如,在 `loading` 狀態下禁用登入按鈕並顯示載入指示器,在 `error` 狀態下顯示錯誤訊息)。
    -   **清晰的邏輯流**: 狀態機使得認證流程的邏輯更加清晰和可預測,減少了條件判斷的複雜性。
    -   **優雅的錯誤處理**: 能夠將認證錯誤與其他應用程式錯誤區分開來,並提供專門的處理和顯示。

---

## 3. 核心流程圖 (Core Flowcharts)

以下流程圖使用 Mermaid.js 語法,展示了認證相關的核心流程及其伴隨的 UI 狀態變化。

### 3.1. 使用者登入流程

```mermaid
graph TD
    A[使用者輸入憑證] --> B{點擊登入};
    B --> C{前端表單驗證}; 
    C -- 成功 --> D{更新狀態: authStatus='loading', error=null};
    D --> E[UI: 禁用登入按鈕/顯示載入指示器];
    E --> F[發送 POST /auth/login 請求];
    F -- 成功 (200 OK, with token) --> G{儲存 Token 到 localStorage};
    G --> H{更新狀態: authStatus='authenticated', user data, error=null};
    H --> I[UI: 導向主應用/儀表板];
    F -- 失敗 (401/403/500) --> J{更新狀態: authStatus='error', error='錯誤訊息'}; 
    J --> K[UI: 顯示錯誤訊息/啟用按鈕];

3.2. 使用者登出流程

graph TD
    A[使用者點擊登出] --> B{更新狀態: authStatus='loading'};
    B --> C[UI: 禁用所有互動/顯示載入];
    C --> D{清除 localStorage 中的 Token};
    D --> E{清除前端狀態};
    E --> F[更新狀態: authStatus='unauthenticated', error=null];
    F --> G[UI: 導向登入頁面];
    G -- (可選) 發送 API 請求 --> H[後端清除 Session/Token];

3.3. 應用程式啟動時的認證檢查流程

graph TD
    A[應用程式啟動] --> B{檢查 localStorage 是否有 Token?};
    B -- 無 Token --> C{更新狀態: authStatus='unauthenticated'};
    C --> D[UI: 顯示登入頁面];
    B -- 有 Token --> E{更新狀態: authStatus='loading'};
    E --> F[UI: 顯示載入指示器];
    F --> G[發送 GET /users/me 請求];
    G -- 成功 --> H{更新狀態: authStatus='authenticated'};
    H --> I[UI: 載入主應用數據/顯示儀表板];
    G -- 失敗 --> J{清除 localStorage 中的 Token};
    J --> K{更新狀態: authStatus='unauthenticated', error='Token 無效/過期'}; 
    K --> L[UI: 顯示登入頁面];

4. 路由與授權:路由守衛 (Routing & Authorization: Route Guards)

4.1. 概念闡述

「路由守衛」就像是應用程式中每個「房間」門口的保全。當使用者嘗試進入某個「房間」(即訪問某個路由或頁面)時,保全會先檢查他們是否具備進入的「通行證」(即是否已認證或具備特定權限)。如果沒有,保全就會阻止他們進入,並將他們帶到指定的地方(例如登入頁面)。

4.2. 職責定義


5. 錯誤處理與 Token 過期策略

5.1. 集中處理

api.js 中的 apiFetch 函式將作為 API 客戶端攔截器,負責攔截所有從後端返回的 API 回應。這是處理 Token 過期和認證錯誤的關鍵點,因為它允許我們在單一位置處理這些全域性的問題,而無需在每個 API 呼叫處重複邏輯。

5.2. 標準流程

apiFetch 偵測到後端返回 401 Unauthorized 狀態碼時,這表示當前使用的 Token 無效或已過期。此時,apiFetch 必須觸發一個全域的登出程序

  1. 清除 localStorage 中的 authToken: 移除無效的 Token,防止其被再次使用。
  2. 重設前端 state 中的認證相關狀態: 將 isAuthenticated 設為 falseuser 設為 nullauthStatus 設為 unauthenticated。這會立即更新 UI,反映使用者已登出。
  3. 將使用者重新導向到登入頁面: 確保使用者被帶到正確的入口點,並可選地顯示一個訊息,告知他們會話已過期。

這樣做的好處是,所有元件都不需要單獨處理 401 錯誤,只需專注於自身的業務邏輯。任何 401 錯誤都會自動觸發一個安全且一致的登出流程。


## Part 4:提交我們的「安全設計圖」

1. **Commit 訊息**: `docs(frontend): Create authentication flow specification`
2. **Commit & Push**!

### 結語:從「功能」到「安全」

再次恭喜!今天,我們為 App 的安全性,打下了最堅實的理論基礎。我們沒有憑感覺去處理這個複雜的流程,而是再次透過 **「文件驅動」**,將所有可能的路徑與邏輯,都預先規劃得一清二楚。

有了這份精密的「安全白皮書」,我們接下來的開發工作將會變得無比順暢。明天,我們將正式拿起工具,**嚴格依據今天的這份流程圖** ,將我們的APP安全性補齊。

Day 29: 【文件 #9】專案的守衛:用 Gemini 規劃「前端認證流程」

發布於 2025年9月17日 (更新於 2025年9月17日) · 約 5 分鐘閱讀 · 2025iThomeIronman Gemini Frontend Authentication JWT Security

安安,我是 ChiYu!

昨天,我們成功地兌現了對使用者的最終承諾,將冰冷的數據轉化為了富有情感的、能啟發洞察的視覺化故事。我們的 App 核心價值已然確立。

但是,我們的 App 現在還像是一個 沒有門鎖的豪宅。雖然內部裝潢精美、功能強大,但任何人都可以隨意進出,這對於一個旨在儲存使用者私密心情與習慣數據的應用來說,是絕對不可接受的。

使用者認證 (Authentication) 流程,是任何嚴肅 Web 應用的基石。它複雜、涉及安全性、且牽一髮而動全身。因此,我們 絕對不能憑感覺去寫!

今天,我們將進行第二個前端的 DDD 循環!我們將扮演一位「資安架構師」,與 Gemini 一同腦力激盪,為這個最關鍵的功能,撰寫一份清晰、專業的**「前端認證流程規格書」**。

Part 1:前端心法:在寫 Code 前,先成為半個資安專家

在我們觸碰任何跟認證相關的程式碼之前,我們必須先在腦中建立起清晰的資安模型。這不僅僅是「使用者體驗」的問題,更是「使用者信任」的基石。

1.1 核心觀念:認證 (Authentication) vs. 授權 (Authorization)

首先,要釐清兩個最常被搞混的概念:

  • 認證 (Authentication - 你是誰?):這個過程是在 驗證你的身份。就像你進入一棟大樓,需要出示你的身份證或門禁卡,向保全證明「我就是住戶 ChiYu」。 登入這個動作,就是最典型的認證。
  • 授權 (Authorization - 你能做什麼?):這個過程是在你 通過認證後決定你有哪些權限。保全確認了你是 ChiYu 後,他還需要知道,你的門禁卡只能打開你家的門,不能打開別人家或頂樓機房的門。在 App 中,這可能意味著普通使用者只能讀取自己的資料,而管理員 (Admin) 則可以讀取所有人的資料。

1.2 現代 Web 的通行證:JWT (JSON Web Token)

在現代 Web App 中,我們如何實現無狀態 (Stateless) 的認證呢?答案就是 JWT

你可以把 JWT 想像成一張 蓋了章的「數位通行證」。當你用帳號密碼成功登入後,伺服器會發給你一張 JWT。這張通行證本身包含了一些資訊(例如你是誰、你的權限是什麼),並且經過伺服器的 數位簽章,確保它沒有被偽造。

之後,你每次要向伺服器請求資料時,只需要在請求中附上這張通行證,伺服器看到上面有自己蓋的章,就知道你是合法的使用者,而不需要每次都重新去資料庫查驗你的帳號密碼。

1.3 OAuth 2.0:安全的「授權代理」

你一定用過「透過 Google / Facebook 登入」的功能。這背後,就是 OAuth 2.0 的功勞。

OAuth 2.0 本質上不是一個「認證」協議,而是一個 **「授權 (Authorization)」**框架。它的核心思想是 「安全的代理授權」

比喻來說: 假設你的 App (我們的 MindTrack) 是一個需要你家(Google 帳戶)鑰匙的「清潔服務公司」。

  • 不安全的作法:你直接把你的 Google 帳號密碼告訴 MindTrack。這太危險了!MindTrack 不僅能打掃你的房間(讀取基本資料),還能動用你的存款、看你的私密信件!
  • OAuth 2.0 的作法:你想請 MindTrack 來打掃時,MindTrack 會把你帶到 Google 的「物業管理處」。你在這裡向 Google 確認:「是的,我同意讓 MindTrack 進入我家,但 只授權他打掃客廳(讀取你的基本個人資料),絕對不准進臥室(讀取你的信件)!」

Google 確認後,不會把你的「萬能鑰匙」給 MindTrack,而是會給他一張 有特定權限、有時效性的「臨時通行證」。MindTrack 拿著這張臨時通行證,就可以來幫你打掃客廳了。

雖然我們的 MVP 不會實作 OAuth 2.0,但理解這個觀念,是你邁向專業開發者的重要一步。

Part 2:Vibe Coding 實戰:撰寫我們的「安全白皮書」

好了,理論武裝完畢!讓我們進入 gemini chat 模式,指揮 AI 為我們撰寫這份至關重要的安全規格書。

【魔法詠唱:設計認證流程】

# 角色 (Role)
你是一位頂尖的資安架構師與資深前端工程師,是 Web 安全、JWT (JSON Web Token) 認證機制、前端路由管理與 API 客戶端設計的權威專家。你致力於在確保安全性的前提下,打造無縫、穩固且可擴展的使用者認證體驗。

# 目標 (Objective)
請根據我提供的專案上下文,為我們的 Web App 設計一份專業、完整、且具備高度可執行性的**「前端認證架構藍圖 (Frontend Authentication Architectural Blueprint)」**。這份文件將作為開發團隊實現所有安全相關功能的唯一真理來源。

# 上下文與關鍵資訊 (Context & Key Information)
* **核心需求**: 我們需要為 App 實現使用者故事 #1:「使用者註冊/登入」。(`@docs/USER_STORIES.md`)
* **後端契約**: 我們後端的 `/auth/login``/auth/register` 端點,在成功後會返回一個包含 `accessToken` (JWT) 的 JSON 物件。(`@docs/API_SPEC.yml`)
* **核心挑戰**: 設計一個既安全又具備良好使用者體驗的前端認證系統。

# 產出格式與要求 (Your Task & Output Requirements)
**請生成一份專業的 Markdown 文件,並嚴格遵循以下大綱結構:**

### 1. **核心原則與架構決策**
* **技術選型與權衡 (Tech Choices & Trade-offs)**:
    * **Token 儲存策略**: 明確我們將選擇 `localStorage` 來儲存 JWT Token。 **請深入分析此決策**:闡述其優點(API 簡單、跨分頁共享),並 **詳細列出其主要安全風險(易受 XSS 攻擊)及對應的基礎緩解措施**(例如:內容安全策略 CSP、輸入淨化)。
    * **API 客戶端攔截器 (API Client Interceptor)**: 說明我們將 **必須**建立一個集中的 `fetch` 封裝函式或使用類似 `axios` 的攔截器。其核心職責是:在 **每個**發出的請求中,自動從 `localStorage` 讀取 Token 並將其附加到 `Authorization` 標頭中。

### 2. **前端認證狀態機 (Frontend Auth State Machine)**
* 說明我們將在前端的 `state` 物件中,維護一個完整的認證狀態機,而不僅僅是一個布林值。
* **狀態定義**:
    * `authStatus: 'idle' | 'loading' | 'authenticated' | 'unauthenticated' | 'error'`
    * `user: { id, name, email } | null`
    * `error: string | null`
* **設計理由**: 簡述為何使用狀態機能夠更優雅地處理 UI 變化(例如,在 `loading` 狀態下禁用登入按鈕)。

### 3. **核心流程圖 (Core Flowcharts)**
* 使用 Mermaid.js 的 `graph TD` 語法,為以下三個核心流程,分別繪製包含 **UI 狀態變化**的清晰流程圖:
    * **使用者登入流程**: 需包含「更新狀態為 loading」、「禁用按鈕」、「API 請求」、「成功後儲存 Token」、「更新狀態為 authenticated」、「失敗後更新狀態為 error」等節點。
    * **使用者登出流程**: 需包含「清除 Token」、「清除本地狀態」、「API 請求(可選)」、「重新導向」。
    * **應用程式啟動時的認證檢查流程**: 需包含「檢查本地 Token」、「驗證 Token 有效性(可選)」、「設定初始狀態」。

### 4. **路由與授權:路由守衛 (Routing & Authorization: Route Guards)**
* **概念闡述**: 深入淺出地解釋什麼是「路由守衛」,並使用「每個房間門口的保全」的比喻。
* **職責定義**:
    * **公開路由 (Public Routes)**: 如 `/login`, `/register`,任何人都可以訪問。
    * **私有路由 (Private Routes)**: 如 `/dashboard`, `/settings`,必須在進入前由「路由守衛」檢查 `state.isAuthenticated` (或 Token 的有效性)。
    * **無權限處理**: 若檢查失敗,路由守衛必須立即將使用者**重新導向 (Redirect)** 至登入頁面。

### 5. **錯誤處理與 Token 過期策略**
* **集中處理**: 定義 API 客戶端攔截器的另一項核心職責:**攔截 API 回應**。
* **標準流程**: 當攔截器偵測到後端返回 `401 Unauthorized` 狀態碼時,它必須觸發一個**全域的登出程序**(清除 Token、重設狀態、重新導向到登入頁),而無需每個元件單獨處理。

### 6. **最終產出**
* 將以上所有內容,生成到 `docs/AUTH_FLOW.md` 檔案中。

Part 3:審核 AI 產出的「安全白皮書」

AI 完成操作後,讓我們來仔細品味一下這份由我們共同創作的、專業的「安全設計圖」。

# 前端認證架構藍圖 (Frontend Authentication Architectural Blueprint)

- **文件版本**: 1.0
- **作者**: Gemini (資安架構師 / 資深前端工程師)
- **狀態**: `草案`

---

## 1. 核心原則與架構決策

### 1.1. 技術選型與權衡 (Token 儲存策略)

我們將選擇 `localStorage` 來儲存 JWT (JSON Web Token)。此決策基於以下考量:

-   **優點**:
    -   **API 簡單易用**: `localStorage` 提供直觀的 `setItem()`, `getItem()`, `removeItem()` 方法,易於開發者操作。
    -   **跨分頁共享**: 儲存在 `localStorage` 中的 Token 可以被同源 (same-origin) 的所有瀏覽器分頁共享,方便使用者在多個分頁間保持登入狀態。
    -   **持久化儲存**: Token 會在瀏覽器關閉後依然存在,使用者無需每次開啟瀏覽器都重新登入,提升使用者體驗。

-   **主要安全風險 (XSS 攻擊)**:
    -   `localStorage` 中的數據**容易受到跨站腳本 (XSS) 攻擊**。一旦攻擊者成功在頁面中注入惡意 JavaScript 程式碼,他們就可以直接存取 `localStorage` 中的所有數據,包括 JWT Token。攻擊者獲取 Token 後,即可冒充使用者發送請求,造成會話劫持 (Session Hijacking)。

-   **基礎緩解措施**:
    -   **內容安全策略 (Content Security Policy, CSP)**: 實施嚴格的 CSP,限制頁面可以載入的腳本、樣式和其他資源的來源。這能有效防禦大多數 XSS 攻擊,因為它阻止了惡意腳本的載入和執行。
    -   **輸入淨化 (Input Sanitization)**: 對所有來自使用者或外部來源的輸入數據進行嚴格的驗證、過濾和淨化,防止惡意程式碼(如 `<script>` 標籤)被儲存到資料庫或直接顯示在頁面上。
    -   **輸出編碼 (Output Encoding)**: 在將任何來自使用者或不可信來源的數據渲染到 DOM 之前,對其進行適當的編碼(例如 HTML 實體編碼)。這可以防止瀏覽器將惡意數據解釋為可執行程式碼。
    -   **Token 有效期短**: 設定 JWT 的有效期限盡可能短(例如 15-30 分鐘)。即使 Token 被盜,其生命週期也有限,降低了攻擊的窗口。應搭配 Refresh Token 機制來無感刷新 Token,但 Refresh Token 應儲存在更安全的 `HttpOnly` Cookie 中,這屬於後端和更複雜的前端範疇。
    -   **不儲存敏感資訊**: JWT 的 Payload 應只包含非敏感的公開資訊(如使用者 ID、角色),不應包含密碼、信用卡號等敏感數據。

### 1.2. API 客戶端攔截器 (API Client Interceptor)

我們將在 `api.js` 模組中建立一個集中的 `apiFetch` 封裝函式(已實現)。其核心職責是:在**每個**發出的請求中,自動從 `localStorage` 讀取 Token 並將其附加到 `Authorization: Bearer <token>` 標頭中。這確保了所有需要認證的 API 請求都能自動攜帶 Token,簡化了業務邏輯的開發。

---

## 2. 前端認證狀態機 (Frontend Auth State Machine)

我們將在前端的 `state` 物件中,維護一個完整的認證狀態機,而不僅僅是一個布林值。這使得 UI 能夠更精確地反映認證過程中的不同階段,提供更優質的使用者體驗。

-   **狀態定義**:
    -   `authStatus: 'idle' | 'loading' | 'authenticated' | 'unauthenticated' | 'error'`
        -   `idle`: 應用程式初始狀態,或認證流程未啟動。
        -   `loading`: 正在進行登入、註冊或 Token 驗證等認證相關的非同步操作。
        -   `authenticated`: 使用者已成功登入並通過驗證,具備訪問受保護資源的權限。
        -   `unauthenticated`: 使用者未登入,或其 Token 無效/已過期,無法訪問受保護資源。
        -   `error`: 在認證過程中發生了錯誤(例如網路問題、憑證錯誤)。
    -   `user: { id, name, email } | null`: 儲存已認證使用者的基本資訊。在 `unauthenticated``error` 狀態下為 `null`    -   `error: string | null`: 儲存認證過程中發生的具體錯誤訊息,用於向使用者顯示。

-   **設計理由**:
    -   **精確的 UI 反饋**: 能夠根據 `authStatus` 精確地控制 UI 元素(例如,在 `loading` 狀態下禁用登入按鈕並顯示載入指示器,在 `error` 狀態下顯示錯誤訊息)。
    -   **清晰的邏輯流**: 狀態機使得認證流程的邏輯更加清晰和可預測,減少了條件判斷的複雜性。
    -   **優雅的錯誤處理**: 能夠將認證錯誤與其他應用程式錯誤區分開來,並提供專門的處理和顯示。

---

## 3. 核心流程圖 (Core Flowcharts)

以下流程圖使用 Mermaid.js 語法,展示了認證相關的核心流程及其伴隨的 UI 狀態變化。

### 3.1. 使用者登入流程

```mermaid
graph TD
    A[使用者輸入憑證] --> B{點擊登入};
    B --> C{前端表單驗證}; 
    C -- 成功 --> D{更新狀態: authStatus='loading', error=null};
    D --> E[UI: 禁用登入按鈕/顯示載入指示器];
    E --> F[發送 POST /auth/login 請求];
    F -- 成功 (200 OK, with token) --> G{儲存 Token 到 localStorage};
    G --> H{更新狀態: authStatus='authenticated', user data, error=null};
    H --> I[UI: 導向主應用/儀表板];
    F -- 失敗 (401/403/500) --> J{更新狀態: authStatus='error', error='錯誤訊息'}; 
    J --> K[UI: 顯示錯誤訊息/啟用按鈕];

3.2. 使用者登出流程

graph TD
    A[使用者點擊登出] --> B{更新狀態: authStatus='loading'};
    B --> C[UI: 禁用所有互動/顯示載入];
    C --> D{清除 localStorage 中的 Token};
    D --> E{清除前端狀態};
    E --> F[更新狀態: authStatus='unauthenticated', error=null];
    F --> G[UI: 導向登入頁面];
    G -- (可選) 發送 API 請求 --> H[後端清除 Session/Token];

3.3. 應用程式啟動時的認證檢查流程

graph TD
    A[應用程式啟動] --> B{檢查 localStorage 是否有 Token?};
    B -- 無 Token --> C{更新狀態: authStatus='unauthenticated'};
    C --> D[UI: 顯示登入頁面];
    B -- 有 Token --> E{更新狀態: authStatus='loading'};
    E --> F[UI: 顯示載入指示器];
    F --> G[發送 GET /users/me 請求];
    G -- 成功 --> H{更新狀態: authStatus='authenticated'};
    H --> I[UI: 載入主應用數據/顯示儀表板];
    G -- 失敗 --> J{清除 localStorage 中的 Token};
    J --> K{更新狀態: authStatus='unauthenticated', error='Token 無效/過期'}; 
    K --> L[UI: 顯示登入頁面];

4. 路由與授權:路由守衛 (Routing & Authorization: Route Guards)

4.1. 概念闡述

「路由守衛」就像是應用程式中每個「房間」門口的保全。當使用者嘗試進入某個「房間」(即訪問某個路由或頁面)時,保全會先檢查他們是否具備進入的「通行證」(即是否已認證或具備特定權限)。如果沒有,保全就會阻止他們進入,並將他們帶到指定的地方(例如登入頁面)。

4.2. 職責定義

  • 公開路由 (Public Routes):

    • 例如 /login, /register。這些路由不需要任何認證,任何人都可以訪問。
    • 路由守衛會確保已登入的使用者不會被困在這些頁面。如果 authStatusauthenticated,則會自動將使用者導向主應用(例如儀表板)。
  • 私有路由 (Private Routes):

    • 例如 /dashboard, /settings, /review。這些路由包含敏感或個人化數據,必須在進入前由「路由守衛」檢查 state.authStatus 是否為 authenticated
  • 無權限處理:

    • 若檢查失敗(即 authStatus 不是 authenticated),路由守衛必須立即將使用者重新導向 (Redirect) 至登入頁面,並可選地附帶一個提示訊息,告知使用者需要登入才能訪問該頁面。

5. 錯誤處理與 Token 過期策略

5.1. 集中處理

api.js 中的 apiFetch 函式將作為 API 客戶端攔截器,負責攔截所有從後端返回的 API 回應。這是處理 Token 過期和認證錯誤的關鍵點,因為它允許我們在單一位置處理這些全域性的問題,而無需在每個 API 呼叫處重複邏輯。

5.2. 標準流程

apiFetch 偵測到後端返回 401 Unauthorized 狀態碼時,這表示當前使用的 Token 無效或已過期。此時,apiFetch 必須觸發一個全域的登出程序

  1. 清除 localStorage 中的 authToken: 移除無效的 Token,防止其被再次使用。
  2. 重設前端 state 中的認證相關狀態: 將 isAuthenticated 設為 falseuser 設為 nullauthStatus 設為 unauthenticated。這會立即更新 UI,反映使用者已登出。
  3. 將使用者重新導向到登入頁面: 確保使用者被帶到正確的入口點,並可選地顯示一個訊息,告知他們會話已過期。

這樣做的好處是,所有元件都不需要單獨處理 401 錯誤,只需專注於自身的業務邏輯。任何 401 錯誤都會自動觸發一個安全且一致的登出流程。


## Part 4:提交我們的「安全設計圖」

1. **Commit 訊息**: `docs(frontend): Create authentication flow specification`
2. **Commit & Push**!

### 結語:從「功能」到「安全」

再次恭喜!今天,我們為 App 的安全性,打下了最堅實的理論基礎。我們沒有憑感覺去處理這個複雜的流程,而是再次透過 **「文件驅動」**,將所有可能的路徑與邏輯,都預先規劃得一清二楚。

有了這份精密的「安全白皮書」,我們接下來的開發工作將會變得無比順暢。明天,我們將正式拿起工具,**嚴格依據今天的這份流程圖** ,將我們的APP安全性補齊。
Part 29 of 32
  1. 01. Day 1: 【啟程】嘿,AI!我們來做個網站,但這次,我們約法三章
  2. 02. Day 2: 【心法篇】開發者的航海圖:什麼是文件驅動開發 (DDD)?
  3. 03. Day 3: 【工具篇 #1】萬丈高樓平地起:建置本地開發環境
  4. 04. Day 4: 【工具篇 #2】程式碼的時光機:Git 與 GitHub 版本控制
  5. 05. Day 5: 【工具篇 #3】終端機裡的魔法:什麼是 Vibe Coding 與 Gemini CLI?
  6. 06. Day 6: 【文件 #1】專案的靈魂:用 Gemini CLI 生成「專案章程」
  7. 07. Day 7: 【文件 #2】使用者的旅程:用 Gemini CLI 描繪「使用者故事」
  8. 08. Day 8: 【文件 #3】系統的心臟:用 Gemini CLI 設計「軟體架構文件」
  9. 09. Day 9: 【文件 #4】數據的家:用 Gemini 規劃「資料庫綱要」
  10. 10. Day 10: 【文件 #5】溝通的契約:用 Gemini 撰寫「Web API 規格書」
  11. 11. Day 11: 【心法 #2】透過AI幫我們生成Prompt
  12. 12. Day 12: 【後端 #1】起手式:AI 代理人 生成模組化的 Flask 專案
  13. 13. Day 13: 【後端 #2】AI 建築師:依藍圖自動建構 CRUD API
  14. 14. Day 14: 【DevOps #1】AI 品管員:設定 GitHub Actions 自動化程式碼檢查
  15. 15. Day 15: 【後端 #3】API 測試:用 Gemini CLI 輔助撰寫 Pytest
  16. 16. Day 16: 【整合篇】後端竣工!回顧與展望
  17. 17. Day 17: 【前端 #0】前端世界的基石: HTML, CSS 與 JavaScript
  18. 18. Day 18: 【文件 #6】網站的風格指南:用 Gemini 定義顏色與字體
  19. 19. Day 19: 【文件 #7】頁面的骨架:用 Gemini 規劃主佈局與元件拆分
  20. 20. Day 20: 【前端 #1】Gemini Canvas 生成UI (還有新的AI建議功能)
  21. 21. Day 21: 【前端 #2】從原型到架構:拆解並整合 AI 生成的 UI 程式碼
  22. 22. Day 22: 【前端 #3】AI 一鍵生成完整 App 靜態 UI
  23. 23. Day 23: 【前端 #4】非同步的藝術:深入 Fetch API 與 Promise
  24. 24. Day 24: 【前端 #5】狀態管理的哲學:讓 UI 成為數據的鏡子
  25. 25. Day 25: 【前端 #6】核心生命週期:一天搞定習慣的「增刪改查」與「打卡」
  26. 26. Day 26: 【前端 #7】用戶體驗的最後一哩路:優雅地處理載入與錯誤
  27. 27. Day 27: 【文件 #8】數據的畫布:用 Gemini 設計「圖表元件規格書」
  28. 28. Day 28: 【前端 #8】兌現承諾:根據規格書 Vibe Coding 關聯性洞察圖表
  29. 29. Day 29: 【文件 #9】專案的守衛:用 Gemini 規劃「前端認證流程」 Current
  30. 30. Day 30: 【前端 #9】建立大門與鑰匙:根據流程圖實現前端使用者認證
  31. 31. Day 31: 【優化篇】代碼的整形外科:JavaScript 模組化與代碼重構
  32. 32. 【完賽感言】左手藍圖,右手魔法:一趟旅程的結束與反思