案例:quote_requests copy
/quote_requests/copy.json 使用「hash 優先,session fallback」。
程式位置
| 專案 | 位置 |
|---|
| 舊專案入口 | get-lancer-php56/app/Plugin/Quotes/Controller/QuoteRequestsController.php::copy() |
| 新專案入口 | pro360_api_82/Endpoint/V1/QuoteRequests.php::copy() |
| 新專案 handler | pro360_api_82/Lib/QuoteRequestCopy/CopyRequestHandler.php::handle() |
資料表關聯
| 資料表 | 用途 | 關聯 |
|---|
quote_requests | 要被複製的 request | quote_requests.id = sourceRequestId |
security_hashes | hash 驗證 | model='QuoteRequest', foreign_id=quote_requests.id |
api_sessions | fallback session 驗證 | session token -> user |
users | 最終 user identity | hash 或 session 都會解析到 user id |
驗證規則
| 順序 | 規則 | 成功時 user id |
|---|
| 1 | 若有 hash,查 security_hashes | 尚未通過 |
| 2 | model 必須是 QuoteRequest | 尚未通過 |
| 3 | foreign_id 必須等於 source request id | security_hashes.user_id |
| 4 | hash 不通過時,檢查 session | $usersDO->id |
| 5 | hash/session 都不通過 | invalid session |
新專案核心程式
if ($hash !== '') {
$hashRecord = (new SecurityHash())->getByHash('QuoteRequest', $hash);
if (is_array($hashRecord) && (int)($hashRecord['foreign_id'] ?? 0) === $sourceRequestId) {
$passed = true;
$resolvedUserId = (int)($hashRecord['user_id'] ?? 0);
}
}
if (!$passed) {
$usersDO = null;
$passed = ApiValidation::hasValidApiSession($request, true, $usersDO);
if ($passed && $usersDO !== null) {
$resolvedUserId = (int)$usersDO->id;
}
}
容易誤判
- hash 字串存在不代表通過,還要比
foreign_id。
- hash 失敗不一定失敗,這支 API 會 fallback session。