手冊首頁 / 認證(登入前) / 忘記密碼 / 重設密碼

忘記密碼 / 重設密碼(Forget / Reset Password)

功能群:認證|密碼變更生命週期、匿名態特性先讀 功能群總覽

事實基準:2026-07-05 從 FE(views/auth/ForgotPassword.vueChangePassword.vue)/ BE(api/auth、jedi-auth 套件)code 掃出;表結構取自 db_schema.jsonpublic schema);error code 對 jedi_auth/common/enum/error_code.py

1. 功能描述

忘記密碼頁讓匿名使用者以 email 申請密碼重設;系統寄出含 token 的連結,使用者於重設密碼頁憑 token 設新密碼。重設密碼頁(ChangePassword.vue)以 type 統一服務忘記密碼 / 首次登入設密碼 / 密碼過期強制變更三情境。本 spec 涵蓋 forget-password 與 reset-password 兩條 route。

主要使用者:忘記密碼 / 需改密碼的匿名使用者。§3 為匿名態(見 _overview §5)。

角色速覽(匿名態,見 _overview §5):

角色 一句話
匿名使用者 申請重設 / 憑 token 設新密碼(/forget-password/reset-password 皆匿名可達)

1.1 功能總覽(本頁全部功能)

# 功能 說明 位置 詳述
1 申請重設 輸入 email → 寄重設連結(5s 冷卻) 忘記密碼頁 UC-FP-01
2 申請節流 5 分鐘內僅一筆待用請求 BE §4
3 token 驗證 進重設頁先驗 token(存在 / 未過期 / 未使用) 重設密碼頁 UC-FP-01
4 情境動態標題 type 0 首次 / 2 忘記 / 3 過期 重設密碼頁 §10
5 新密碼設定 ≥12 字 + 大小寫 + 數字複雜度 重設密碼頁 §4
6 確認密碼 須與新密碼相符 重設密碼頁 §6.2
7 密碼防重用 不可與近 3 次相同 BE §4
8 完成轉登入 成功清 localStorage → 轉登入 重設密碼頁 UC-FP-01

UC(§2)展開 忘記 → token → 重設 完整鏈路(UC-FP-01)。

2. Use Case

角色速覽(匿名態,見 _overview §5):

角色 一句話
匿名使用者 申請重設 / 憑 token 設新密碼(/forget-password/reset-password 皆匿名可達)

流程圖視覺慣例:菱形 = 判斷、橘底 = 例外 / 非同步、紅框 = 錯誤(標 error code)、綠框 = 成功終點、虛線 = 頻外(email)。

UC-FP-01 忘記密碼 → email token → 重設密碼

項目 內容
角色 匿名使用者
前置條件 忘記:email 對應啟用帳號;重設:持有效 token(url ?uid=
產出 / 後置條件 忘記 → 建 user_change_password_request(type=2, status=0, expired=+30 分)+ 寄信;重設 → bcrypt 更新密碼、寫變更 log、token 標 status=1
uc_fp_01 UC-FP-01 忘記密碼 → email token → 重設密碼 forget 忘記密碼頁:輸入 email req POST /forget-password {email} forget->req throttle 5 分鐘內已申請? req->throttle terr AUTH_429002 5 分鐘內已申請 throttle->terr create 建 user_change_password_request type=2 忘記 / status=0 / expired=+30 分鐘 寄信含 /reset-password?uid={token} throttle->create reset 重設密碼頁(?uid=token) create->reset 使用者點信中連結 verify GET /user/change-pwd-req/{uid} 驗 token reset->verify valid token 有效?(存在/未過期/未使用) verify->valid verr AUTH_401003 無效 / 401005 過期 / 401007 已使用 valid->verr submit 輸入新密碼(≥12+複雜度)+ 確認 POST /user/change-pwd-by-req valid->submit reuse 與近 3 次相同 / 兩次不符? submit->reuse rerr AUTH_401009 與舊密碼相同 / 401010 不相符 reuse->rerr done bcrypt 更新 users.password 寫 user_change_pwd_logs · token status=1 → 轉登入 reuse->done
UC-FP-01:忘記(節流)→ email token → 重設(token 驗證 + 密碼防重用)

3. 權限矩陣

匿名態(見 _overview §5):

操作 FE 判定 BE 強制 BE 檢查位置
申請重設 匿名頁(Authorization: null 無 JWT;email 存在檢查 + 5 分節流 api/auth/routes/change_password_route.py::ForgetPasswordRoute
驗 token 匿名頁 無 JWT;token 有效性 同檔 UserChangePasswordRequestRoute(GET)
設新密碼 匿名頁 無 JWT;token 有效性 + 密碼相符 + 防重用 同檔 ChangePasswordByChangeRequestRoute

token(uid)是重設端點的唯一憑證——無 JWT。故 token 的過期 / single-use / 節流是安全關鍵(見 §12)。

4. 狀態機與前置條件

密碼變更請求生命週期見 _overview §4。本頁 gate:

gate 效果 出處
email 不存在 AUTH_404002(使用者信箱不存在)——回應碼洩漏帳號存在性(§12) jedi_auth ...user_change_password_service::request_change_password
5 分鐘內已申請 AUTH_429002(5 分鐘內已申請),舊請求標 used ..._request_domain_service::verify_user_change_password_apply
token 不存在 AUTH_401003 verify_and_get_user_change_password_request
token 過期(>30 分) AUTH_401005(變更密碼請求已過期) 同上
token 已使用 AUTH_401007(變更密碼請求已使用) 同上
新密碼 = 近 3 次 AUTH_401009(新密碼與舊密碼相同) ..._log_domain_service::verify_user_change_password_log
密碼與確認不符 AUTH_401010(密碼與確認密碼不相同) route 前置檢查
密碼政策 ≥12 字 + 大小寫 + 數字(僅 FE vuelidate 檢,BE 未強制內容,§12) ChangePassword.vuepasswordComplexity regex)

5. UI 設計

📸 實際畫面截圖待補(一律亮色模式 + 登出態擷取;截圖另有專責 session)。預計補到 assets/img/: ① 忘記密碼頁 forgot-password.png ② 重設密碼頁(密碼規則提示) reset-password.png ③ token 失效全頁錯誤 reset-token-error.png

版面骨架與區塊職責:忘記密碼卡(email 申請 + 節流/防列舉 + 建請求寄信,→ UC-FP-01)與重設密碼卡(token 驗證 + 動態標題 + 新密碼設定,→ UC-FP-01)。

匿名入口:忘記密碼頁(/forget-password)→ email token → 重設密碼頁(/reset-password) 同一重設頁以 type 服務三情境:首次(0) / 忘記(2) / 過期(3) 開啟:UC-FP-01 忘記密碼 → email token → 重設密碼 忘記密碼卡:email 申請重設 email 輸入 送出 → POST /forget-password 節流 + 帳號列舉防護(條件層) 5 分鐘內僅一筆待用請求(AUTH_429002,舊請求標 used) 送出後 5s 冷卻(防連點) email 不存在仍回成功 toast(BE 回碼不同,§12 已知坑) 建重設請求 + 寄信(頻外) user_change_password_request(type=2, expired=+30min) 連結:{system_url}/reset-password?uid={uid} → UC-FP-01(點我開啟) POST /forget-password(email 存在檢查 → 節流 → 建請求 + 寄信) 開啟:UC-FP-01 忘記密碼 → email token → 重設密碼 重設密碼卡:token 驗證 + 新密碼 進頁先驗 token(url ?uid=) 存在(401003) / 未過期(401005,30分) / 未使用(401007) 失敗 → 全頁錯誤 + 返回登入(隱藏表單) 情境動態標題:type 0 首次 / 2 忘記 / 3 過期(90天) 新密碼(≥12 字+大小寫+數字,FE 檢) 確認密碼(須與新密碼相符) 規則清單提示:12+ 字 / 大小寫 / 數字;不可與近 3 次相同 設定新密碼 → POST /user/change-pwd-by-req 成功清 localStorage → 轉登入 ・ → UC-FP-01(點我開啟) GET /user/change-pwd-req/{uid} ・ POST /user/change-pwd-by-req 彩色=主要互動區塊,整塊可點擊跳轉本頁 UC/§6|灰=本頁結構|虛線框=條件顯示層(token 失效、節流冷卻) API 僅列代表性 2~3 條,完整規格見 §6;三情境(首次/忘記/過期)共用同一重設頁與同一 POST 端點
忘記密碼頁(申請卡:節流/防列舉)+ 重設密碼頁(重設卡:token 驗證/動態標題/新密碼),可點跳轉 UC-FP-01

狀態呈現:忘記頁送出後 5s 冷卻(防連點);重設頁進頁先驗 token,失效則顯示全頁錯誤 + 返回登入(隱藏表單);密碼規則以側欄清單提示(12+ 字 / 大小寫 + 數字)。無 socket

6. API 規格

Envelope:成功 {"status": true, "data": …}、失敗 {"error_code": "AUTH_…", "msg": "…"}

6.1 總清單(本頁呼叫的全部 endpoint)

分類 Method + Path 說明 完整規格
申請 POST /forget-password 以 email 申請重設(建請求 + 寄信) §6.2
驗 token GET /user/change-pwd-req/{uid} 驗證重設 token 並取 type §6.2
設密碼 POST /user/change-pwd-by-req 憑 token 設新密碼 §6.2

6.2 核心 endpoint(欄位對照 serializer / service,出處標段末)

[POST] /forget-password

Request:

{ "email": "string" }

流程:檢查 email 存在(不存在 AUTH_404002)→ 5 分節流(AUTH_429002)→ 建 user_change_password_requesttype=2 忘記 / status=0 / expired=now+30min / uid=UUID token)→ 若 notification_service 存在,寄信含 {system_url}/reset-password?uid={uid}&lang=。Response:請求摘要(uid / user_id / type / status / expired / created_at)。出處:api/auth/routes/change_password_route.py::ForgetPasswordRoutejedi_auth ...user_change_password_service::request_change_password

[GET] /user/change-pwd-req/{uid} — 驗 token

驗證:存在(AUTH_401003)/ 未過期(AUTH_401005)/ 未使用(AUTH_401007)→ 回請求(含 type 供動態標題)。出處:change_password_route.py::UserChangePasswordRequestRoute..._request_domain_service::verify_and_get_user_change_password_request

[POST] /user/change-pwd-by-req — 設新密碼

Request:

{
  "req_uid": "string",
  "password": "string",
  "confirm_password": "string"
}

流程:新密碼與確認相符檢查(否則 AUTH_401010)→ 重驗 token → 取 user → 防重用(bcrypt 比近 3 次,相同擋 AUTH_401009)→ bcrypt(per-user salt)更新 users.password → 寫 user_change_pwd_logs → token status=1。以 @transaction 原子完成。出處:change_password_route.py::ChangePasswordByChangeRequestRoute..._service::change_password_by_request

7. 前端檔案地圖(compliance-manager-fe/)

檔案 角色
src/views/auth/ForgotPassword.vue 忘記密碼頁(email 輸入 + 送出 + 冷卻)
src/views/auth/ChangePassword.vue 重設密碼頁(token 驗證 + 新密碼 + 動態標題)
src/config/router/index.js:677-685 route forget-password/forget-password)、reset-password/reset-password
src/config/api/api.js FORGET_PWD/forget-password)/ CHANGE_PWD_REQ/user/change-pwd-req)/ CHANGE_PWD_BY_REQ/user/change-pwd-by-req
src/config/locales/i18n/*/error-code.json CE60001/CE61006/CE61007/CE61010 → i18n 訊息

8. 後端檔案地圖(本頁核心鏈路)

鏈路 Route App Service 底層
申請 api/auth/routes/change_password_route.py::ForgetPasswordRoute jedi_auth ...user_change_password_service::request_change_password user_change_password_request 寫 + jedi-notification 寄信
驗 token 同檔 UserChangePasswordRequestRoute ..._request_domain_service::verify_and_get_... user_change_password_request
設密碼 同檔 ChangePasswordByChangeRequestRoute ..._service::change_password_by_request users(bcrypt)+ user_change_pwd_logs 寫 + token 標 used

DDD 提醒:密碼變更核心 domain 在 jedi-auth 外部套件;主專案 route 做 HTTP 邊界。change_password_by_request@transaction 包住「更新密碼 + 寫 log + token 標 used」原子。

9. DB

9.1 資料表總清單(本頁讀寫的全部表)

讀/寫 說明 欄位詳述
public.user_change_password_request 讀 / 重設請求(token=uid、type、status 0→1、expired) _overview §2
public.user_change_pwd_logs 密碼變更歷史(防重用比對來源) _overview §2
public.users 讀 / (password) bcrypt 更新密碼;email 存在檢查 _overview §2

9.2 ER 圖(本頁讀寫範圍)

_overview §2 認證資料模型assets/au-auth-data-model.dot)——本頁 users → user_change_password_request → user_change_pwd_logs。

9.3 核心欄位

user_change_password_request(uid / user_id / type 0-1-2-3-9 / status 0-1 / expired)與 user_change_pwd_logs(user_id / type / password)欄位見 _overview §2 / §4。密碼以 bcrypt + per-user salt 雜湊存 users.password

10. 頁面邏輯與資料對應

流程:忘記頁 email → POST /forget-password(不論帳號是否存在,FE 皆顯示成功 toast)→ 使用者收信點連結 → 重設頁 ?uid=tokenGET /user/change-pwd-req/{uid} 驗 token 並依 type 顯標題 → 填新密碼 → POST /user/change-pwd-by-req → 成功清 localStorage 轉登入。

情境動態標題ChangePassword.vue,依 type):0 首次註冊設密碼 / 2 忘記密碼重設 / 3 密碼過期(90 天)強制變更——同一頁 + 同一 POST 端點服務三情境。

關鍵欄位對應(FE ↔︎ API):

畫面元素 FE state API 欄位
email 輸入 user_email email
token(url) pwd.req_uidroute.query.uid req_uid / path uid
新密碼 / 確認 password / confirm_password password / confirm_password
動態標題 reqData.type type(0/2/3)

錯誤對應AUTH_401003(CE60001 無效)/ 401005(CE61006 過期)/ 401007(CE61007 已使用)/ 401009(CE61010 與舊密碼相同)/ 401010(不相符)/ 404002(信箱不存在)/ 429002(5 分節流)→ toast / 全頁錯誤。

11. 背景行為與外部依賴

類型 內容
Email 寄送 jedi-notification NotificationService.send_mail_notification(is_html);SMTP 設定讀 ROOT tenant(tenant_id=1)system_config 的 SMTP key(host/port/from/user/secret/tls);若 notification_service 為 None 或 SMTP 未設 → 靜默 no-op(dev 常見)(§12)
密碼雜湊 bcrypt + per-user salt(users.salt);防重用比近 3 筆 user_change_pwd_logs
稽核 申請記 EventCode.USER_RESET_PASSWORD
jedi-* 套件 jedi-auth(密碼變更 domain / service / 錯誤碼)、jedi-notification(SMTP)、jedi-common@transaction / 例外)
Socket 本頁
系統參數 密碼政策(≥12 + 複雜度)目前只在 FE regex;BE 未強制內容(§12)

12. 邊界情況與已知坑

  1. 帳號列舉風險(安全):/forget-password 對不存在 email 回 AUTH_404002(404),存在則 200——FE 雖統一顯示成功 toast,但回應狀態碼不同,攻擊者可據此列舉有效 email。修法:不存在 email 也回 200(不洩漏)。
  2. 密碼政策僅 FE 強制:≥12 字 + 大小寫 + 數字由 ChangePassword.vue vuelidate 檢;BE route 只驗欄位型別、不驗密碼內容——繞過 FE 可設弱密碼。應在 BE 補政策檢查。
  3. token 30 分過期 + single-useexpired=now+30minstatus 0→1;已用 / 過期不可再用。無延長機制。
  4. 5 分節流:每使用者同時僅一筆待用 type=2 請求;新申請把舊的標 used。防濫發但也意味舊連結會失效。
  5. email 寄送可能 no-opnotification_service 為 None 或 SMTP 未設時靜默不寄(dev 環境常見)——測試重設需直接查 DB 拿 user_change_password_request.uid 組連結。
  6. 三情境共用一頁:type 0(首次)/ 2(忘記)/ 3(過期)都走 ChangePassword.vue + 同一 POST;改流程要顧及三情境。
  7. 重設頁清 localStorage:成功後清 localStorage 再轉登入——避免殘留舊 token / 狀態。

13. 開發與驗證

  • 跑起來:BE python main_socketio.py(port 8000,log 在 log/app.log);FE 在 compliance-manager-fe/ 起 Vite dev server。email 寄送需 ROOT tenant SMTP 設定,否則 no-op。BE 改 service code 後必須重啟
  • 測試帳號:dev 環境登入帳號密碼見 .env / 部署文件
  • 導航路徑:登入頁「忘記密碼」→ /forget-password;重設連結 /reset-password?uid=<token>
  • 前置資料:忘記需啟用帳號 + 有 email;重設需有效 token(dev 無 SMTP 時直接查 user_change_password_request.uid 組連結)
  • E2Ecompliance-manager-test/ repo;以 忘記密碼 / reset password 搜尋 feature 檔
  • 相關文件:登入 / MFA 見 登入、密碼變更生命週期見 _overview §4;DB / API 全量見 GAI-SD-02/04(Security Design)