feat(auth): 增加管理员登录的速率限制和错误处理

This commit is contained in:
Jeff Gu committed 2026-04-14 17:01:07 +08:00
1 parent 8336649477
commit 3dc1fed1c1
5 files changed
+460 -3

No files matched your search

+43 -2
View File
@@ -59,6 +59,19 @@ do_get() { curl -s -w "\n%{http_code}" "$@"; }
do_post() { curl -s -w "\n%{http_code}" -X POST "$@"; }
reset_mock_inspection() { curl -s -X POST "$MOCK_API/__reset" > /dev/null; }
get_mock_inspection() { curl -sG "$MOCK_API/__inspect" --data-urlencode "key=$1"; }
set_system_config_disabled() {
"${DB_EXEC[@]}" "INSERT OR REPLACE INTO settings (key, value) VALUES ('SYSTEM_CONFIG', '{\"displayDecimals\":6,\"adminSecurity\":{\"enabled\":false,\"telegramBotToken\":\"\",\"telegramChatId\":\"\",\"verifiedFingerprint\":\"\",\"verifiedAt\":null},\"apiDocs\":{\"enabled\":true}}')" > /dev/null 2>&1
}
set_system_config_with_telegram() {
local bot_token="$1" chat_id="$2" fingerprint
fingerprint=$(node -e "const source = process.argv[1] + '::' + process.argv[2]; let hash = 2166136261; for (let index = 0; index < source.length; index += 1) { hash ^= source.charCodeAt(index); hash = Math.imul(hash, 16777619); } process.stdout.write(source ? 'tgv1-' + ((hash >>> 0).toString(16)) : '');" "$bot_token" "$chat_id")
"${DB_EXEC[@]}" "INSERT OR REPLACE INTO settings (key, value) VALUES ('SYSTEM_CONFIG', '{\"displayDecimals\":6,\"adminSecurity\":{\"enabled\":true,\"telegramBotToken\":\"$bot_token\",\"telegramChatId\":\"$chat_id\",\"verifiedFingerprint\":\"$fingerprint\",\"verifiedAt\":\"2026-04-14T00:00:00.000Z\"},\"apiDocs\":{\"enabled\":true}}')" > /dev/null 2>&1
}
seed_blocked_rate_limit() {
local category="$1" bucket_id="$2" attempts="$3" blocked_until="$4" now_iso
now_iso=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
"${DB_EXEC[@]}" "INSERT OR REPLACE INTO admin_rate_limit (bucket_key, category, bucket_id, window_started_at, attempts, blocked_until, last_event_at) VALUES ('$category:$bucket_id', '$category', '$bucket_id', '$now_iso', $attempts, '$blocked_until', '$now_iso')" > /dev/null 2>&1
}
if [[ -f ".dev.vars" ]]; then
set -a
@@ -67,6 +80,8 @@ if [[ -f ".dev.vars" ]]; then
set +a
fi
LOGIN_PAYLOAD=$(printf '{"token":"%s"}' "$ADMIN_TOKEN")
echo ""
echo "========================================="
echo " E2E Tests with Mock Upstream"
@@ -241,9 +256,8 @@ assert_http "quota exceeded → 402" "402" "Quota exceeded" "$R"
echo ""
echo "--- Admin session cookie ---"
"${DB_EXEC[@]}" "INSERT OR REPLACE INTO settings (key, value) VALUES ('SYSTEM_CONFIG', '{\"displayDecimals\":6,\"adminSecurity\":{\"enabled\":false,\"telegramBotToken\":\"\",\"telegramChatId\":\"\",\"verifiedFingerprint\":\"\",\"verifiedAt\":null},\"apiDocs\":{\"enabled\":true}}')" > /dev/null 2>&1
set_system_config_disabled
COOKIE_JAR=$(mktemp)
LOGIN_PAYLOAD=$(printf '{"token":"%s"}' "$ADMIN_TOKEN")
R=$(do_post "$API/api/admin/auth/login" -H "Content-Type: application/json" -c "$COOKIE_JAR" -d "$LOGIN_PAYLOAD")
assert_http "admin login → 200" "200" "\"requiresVerification\":false" "$R"
@@ -261,6 +275,32 @@ assert_http "admin cookie invalid after logout" "401" "Unauthorized" "$R"
rm -f "$COOKIE_JAR"
# ---- Admin anti-bruteforce ----
echo ""
echo "--- Admin anti-bruteforce ---"
set_system_config_disabled
LIMIT_IP="203.0.113.70"
"${DB_EXEC[@]}" "DELETE FROM admin_rate_limit" > /dev/null 2>&1
for attempt in 1 2 3 4 5; do
R=$(do_post "$API/api/admin/auth/login" -H "Content-Type: application/json" -H "CF-Connecting-IP: $LIMIT_IP" -d '{"token":"bad-token"}')
assert_http "admin invalid token attempt $attempt → 401" "401" "管理员令牌无效" "$R"
done
R=$(do_post "$API/api/admin/auth/login" -H "Content-Type: application/json" -H "CF-Connecting-IP: $LIMIT_IP" -d '{"token":"bad-token"}')
assert_http "admin invalid token freeze → 429" "429" "管理员登录失败次数过多" "$R"
# ---- Telegram notification throttle ----
echo ""
echo "--- Telegram notification throttle ---"
THROTTLE_IP="203.0.113.71"
THROTTLE_UNTIL=$(date -u -d "+15 minutes" +"%Y-%m-%dT%H:%M:%SZ")
set_system_config_with_telegram "dummy-bot-token" "123456"
"${DB_EXEC[@]}" "DELETE FROM admin_rate_limit" > /dev/null 2>&1
seed_blocked_rate_limit "admin-telegram-code:ip" "$THROTTLE_IP" 99 "$THROTTLE_UNTIL"
R=$(do_post "$API/api/admin/auth/login" -H "Content-Type: application/json" -H "CF-Connecting-IP: $THROTTLE_IP" -d "$LOGIN_PAYLOAD")
assert_http "telegram code notification throttle → 429" "429" "验证码发送过于频繁" "$R"
# ---- Error recovery ----
echo ""
echo "--- Error recovery ---"
@@ -284,6 +324,7 @@ done
for key in sk-mock-all sk-mock-openai sk-mock-quota; do
"${DB_EXEC[@]}" "DELETE FROM api_token WHERE key = '$key'" > /dev/null 2>&1
done
"${DB_EXEC[@]}" "DELETE FROM admin_rate_limit; DELETE FROM admin_login_challenge; DELETE FROM admin_session; DELETE FROM settings WHERE key = 'SYSTEM_CONFIG'" > /dev/null 2>&1
echo "Cleanup done."
exit $FAIL
+1
View File
@@ -12,6 +12,7 @@ echo "Setting up test channels and tokens..."
# Warm up the worker so schema migrations run against the same local D1 database.
curl -s "$API_URL/api/admin/channel" > /dev/null 2>&1 || true
"${DB_EXEC[@]}" "DELETE FROM admin_rate_limit; DELETE FROM admin_login_challenge; DELETE FROM admin_session; DELETE FROM settings WHERE key = 'SYSTEM_CONFIG'" > /dev/null 2>&1 || true
# Channel: openai type
"${DB_EXEC[@]}" "INSERT OR REPLACE INTO channel_config (key, value) VALUES ('test-openai', '{\"name\":\"test-openai\",\"type\":\"openai\",\"endpoint\":\"$MOCK\",\"api_key\":\"mock-key\",\"deployment_mapper\":{\"gpt-4o\":\"gpt-4o\",\"gpt-4\":\"gpt-4\"}}')"