Merge pull request 'feat: reat limit' (#1) from feat/envoy-request-limit into main
Reviewed-on: http://103.236.53.208:3000/juwan/juwan-backend/pulls/1
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
deploy/dev/script/*.sh text eol=lf
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 测试 Envoy Lua 双 Cookie XSRF + 登录接口 + 限流头
|
||||||
|
# 用法:
|
||||||
|
# ./test-login-xsrf-rl.sh [BASE_URL] [WARM_PATH] [LOGIN_PATH] [COUNT] [INTERVAL]
|
||||||
|
# 环境变量:
|
||||||
|
# INSECURE=1 # https 自签时跳过校验
|
||||||
|
# TOKEN_HEADER=xsrf-token
|
||||||
|
# USERNAME=testUser
|
||||||
|
# PASSWORD=string
|
||||||
|
# PHONE=string
|
||||||
|
# REMEMBER=true # true/false
|
||||||
|
# DATA='{"username":"..."}' # 直接提供完整 JSON,将覆盖上面四项
|
||||||
|
#
|
||||||
|
# 例子:
|
||||||
|
# ./test-login-xsrf-rl.sh http://127.0.0.1:8080 /healthz /api/v1/auth/login 25 0.1
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BASE_URL="${1:-http://127.0.0.1:8080}"
|
||||||
|
WARM_PATH="${2:-/healthz}"
|
||||||
|
LOGIN_PATH="${3:-/api/v1/auth/login}"
|
||||||
|
COUNT="${4:-20}"
|
||||||
|
INTERVAL="${5:-0.05}"
|
||||||
|
|
||||||
|
METHOD="POST"
|
||||||
|
CONTENT_TYPE="application/json"
|
||||||
|
|
||||||
|
TOKEN_HEADER="${TOKEN_HEADER:-xsrf-token}"
|
||||||
|
TOKEN_COOKIE="__Host-XSRF-TOKEN"
|
||||||
|
GUARD_COOKIE="__Host-XSRF-GUARD"
|
||||||
|
|
||||||
|
USERNAME="${USERNAME:-testUser}"
|
||||||
|
PASSWORD="${PASSWORD:-string}"
|
||||||
|
PHONE="${PHONE:-string}"
|
||||||
|
REMEMBER="${REMEMBER:-true}"
|
||||||
|
|
||||||
|
INSECURE="${INSECURE:-}"
|
||||||
|
|
||||||
|
CURL_COMMON=(-sS -L)
|
||||||
|
[[ -n "${INSECURE}" ]] && CURL_COMMON+=(-k)
|
||||||
|
|
||||||
|
tmpdir="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$tmpdir"' EXIT
|
||||||
|
hdr="$tmpdir/hdr"
|
||||||
|
|
||||||
|
echo "# Base=${BASE_URL} Warm=${WARM_PATH} Login=${LOGIN_PATH} Count=${COUNT} Interval=${INTERVAL}s"
|
||||||
|
|
||||||
|
# 构造请求体(优先使用 DATA;否则用变量拼装)
|
||||||
|
build_data() {
|
||||||
|
if [[ -n "${DATA:-}" ]]; then
|
||||||
|
DATA_PAYLOAD="${DATA}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 规范化 REMEMBER 为 true/false
|
||||||
|
case "${REMEMBER,,}" in
|
||||||
|
true) REMEMBER=true ;;
|
||||||
|
false) REMEMBER=false ;;
|
||||||
|
*) REMEMBER=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if command -v jq >/dev/null 2>&1; then
|
||||||
|
DATA_PAYLOAD="$(
|
||||||
|
jq -n \
|
||||||
|
--arg username "$USERNAME" \
|
||||||
|
--arg password "$PASSWORD" \
|
||||||
|
--arg phone "$PHONE" \
|
||||||
|
--argjson remember "$REMEMBER" \
|
||||||
|
'{username:$username,password:$password,phone:$phone,remember:$remember}'
|
||||||
|
)"
|
||||||
|
else
|
||||||
|
# 无 jq 的简易拼装(注意变量里如含双引号会破坏 JSON,生产建议安装 jq)
|
||||||
|
DATA_PAYLOAD=$(cat <<JSON
|
||||||
|
{"username":"$USERNAME","password":"$PASSWORD","phone":"$PHONE","remember":$REMEMBER}
|
||||||
|
JSON
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
warm_set_cookies() {
|
||||||
|
local url="${BASE_URL}${WARM_PATH}"
|
||||||
|
echo "# 预热: GET ${url} 以获得 CSRF 双 Cookie"
|
||||||
|
curl "${CURL_COMMON[@]}" -X GET -D "$hdr" -o /dev/null "$url" || true
|
||||||
|
|
||||||
|
# 解析 Set-Cookie
|
||||||
|
local out
|
||||||
|
out=$(awk '
|
||||||
|
{
|
||||||
|
line=$0; gsub("\r","",line);
|
||||||
|
low=tolower(line);
|
||||||
|
if (index(low,"set-cookie:")==1) {
|
||||||
|
sub(/^[Ss]et-[Cc]ookie:[ ]*/, "", line);
|
||||||
|
split(line, p, /;/); split(p[1], kv, /=/);
|
||||||
|
name=tolower(kv[1]); val=kv[2];
|
||||||
|
if (name=="__host-xsrf-token") token=val;
|
||||||
|
if (name=="__host-xsrf-guard") guard=val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END{
|
||||||
|
if (token) printf("TOKEN=%s\n", token);
|
||||||
|
if (guard) printf("GUARD=%s\n", guard);
|
||||||
|
}' "$hdr" || true)
|
||||||
|
|
||||||
|
eval "$out" || true
|
||||||
|
if [[ -z "${TOKEN:-}" || -z "${GUARD:-}" ]]; then
|
||||||
|
echo "!! 未从响应中解析到 CSRF Cookie,检查 Lua 过滤器是否生效或是否命中过滤链。"
|
||||||
|
echo "响应头预览:"; head -n 50 "$hdr"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
COOKIE_HEADER="${TOKEN_COOKIE}=${TOKEN}; ${GUARD_COOKIE}=${GUARD}"
|
||||||
|
echo "# 已获取 Cookie: ${COOKIE_HEADER}"
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_rl_headers() {
|
||||||
|
local LIMIT REMAIN RESET RLED
|
||||||
|
LIMIT=$(grep -i '^x-ratelimit-limit:' "$hdr" 2>/dev/null | head -n1 | awk '{print $2}' | tr -d '\r' || true)
|
||||||
|
REMAIN=$(grep -i '^x-ratelimit-remaining:' "$hdr" 2>/dev/null | head -n1 | awk '{print $2}' | tr -d '\r' || true)
|
||||||
|
RESET=$(grep -i '^x-ratelimit-reset:' "$hdr" 2>/dev/null | head -n1 | awk '{print $2}' | tr -d '\r' || true)
|
||||||
|
RLED=$(grep -i '^x-envoy-ratelimited:' "$hdr" 2>/dev/null | head -n1 | awk '{print $2}' | tr -d '\r' || true)
|
||||||
|
printf "limit=%s remaining=%s reset=%s ratelimited=%s" "${LIMIT:--}" "${REMAIN:--}" "${RESET:--}" "${RLED:-no}"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_request() {
|
||||||
|
local with_header="$1" # yes/no
|
||||||
|
local url="${BASE_URL}${LOGIN_PATH}"
|
||||||
|
rm -f "$hdr"
|
||||||
|
|
||||||
|
if [[ "$with_header" == "yes" ]]; then
|
||||||
|
CODE=$(curl "${CURL_COMMON[@]}" -X "$METHOD" \
|
||||||
|
-H "Content-Type: ${CONTENT_TYPE}" \
|
||||||
|
-H "Cookie: ${COOKIE_HEADER}" \
|
||||||
|
-H "${TOKEN_HEADER}: ${TOKEN}" \
|
||||||
|
--data "$DATA_PAYLOAD" \
|
||||||
|
-D "$hdr" -o /dev/null -w "%{http_code}" \
|
||||||
|
"$url")
|
||||||
|
else
|
||||||
|
CODE=$(curl "${CURL_COMMON[@]}" -X "$METHOD" \
|
||||||
|
-H "Content-Type: ${CONTENT_TYPE}" \
|
||||||
|
-H "Cookie: ${COOKIE_HEADER}" \
|
||||||
|
--data "$DATA_PAYLOAD" \
|
||||||
|
-D "$hdr" -o /dev/null -w "%{http_code}" \
|
||||||
|
"$url")
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s code=%s " "$(date '+%H:%M:%S')" "${CODE}"
|
||||||
|
extract_rl_headers
|
||||||
|
printf "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1) 构造登录请求体
|
||||||
|
build_data
|
||||||
|
echo "# 登录请求体: ${DATA_PAYLOAD}"
|
||||||
|
|
||||||
|
# 2) 预热拿 Cookie
|
||||||
|
warm_set_cookies
|
||||||
|
|
||||||
|
# 3) 负例:不带 xsrf-token 头(应 403)
|
||||||
|
echo "# 负例:不带 XSRF 头,预期 403"
|
||||||
|
do_request "no"
|
||||||
|
|
||||||
|
# 4) 正例:带齐 Cookie + xsrf-token,循环观察限流头
|
||||||
|
echo "# 正例:带齐 Cookie 与 XSRF 头,开始压测以观测限流头"
|
||||||
|
for i in $(seq 1 "${COUNT}"); do
|
||||||
|
printf "#%02d " "$i"
|
||||||
|
do_request "yes"
|
||||||
|
sleep "${INTERVAL}"
|
||||||
|
done
|
||||||
Reference in New Issue
Block a user