D:\free_soft\python-3.11.9\python.exe C:/Users/Administrator/AppData/Roaming/JetBrains/IntelliJIdea2024.3/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py --path E:\versionManager\sources\java\idea\python\app-api\test\test_api_flow.py
Testing started at 23:39 ...
Launching pytest with arguments E:\versionManager\sources\java\idea\python\app-api\test\test_api_flow.py --no-header --no-summary -q in E:\versionManager\sources\java\idea\python\app-api\test
============================= test session starts =============================
collecting ... collected 24 items
test_api_flow.py::test_get_access_token PASSED [ 4%]
===== 测试:获取飞书access_token =====
已清除旧Token缓存
请求头:{'X-Appid': 'feishu_mock_appid', 'X-Appsecret': 'feishu_mock_secret_999'}
响应结果:{'errcode': 0, 'errmsg': 'success', 'access_token': 'f36b862e221241d4bdc280b4399f74d5', 'expires_in': 7200, 'token_type': 'Bearer', 'note': 'access_token需配合IP白名单和Authorization头使用'}
test_api_flow.py::test_common_interface FAILED [ 8%]
===== 测试:调用飞书普通数据接口 =====
请求头:{'Authorization': 'Bearer d67689836d094765b7252cae531fb600', 'X-Forwarded-For': '127.0.0.1'}
响应结果:{'detail': '服务器内部错误'}
test_api_flow.py:172 (test_common_interface)
500 != 200
Expected :200
Actual :500
<Click to see difference>
def test_common_interface():
"""测试调用飞书普通接口(仅Token鉴权,正向测试)"""
# 打印测试场景描述
print(f"\n===== 测试:调用飞书普通数据接口 =====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
access_token = get_valid_token()
# 拼接普通数据接口地址,指定data_id为100
url = f"{BASE_URL}/api/v1/data/100"
# 构造请求头,包含Token和白名单IP
headers = {
"Authorization": f"Bearer {access_token}",
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求调用普通接口
response = requests.get(url, headers=headers)
# 将响应结果转换为JSON格式
result = response.json()
# 打印调试信息,便于验证
print(f"请求头:{headers}")
print(f"响应结果:{result}")
# 断言响应状态码为200
> assert response.status_code == 200
E assert 500 == 200
E + where 500 = <Response [500]>.status_code
test_api_flow.py:199: AssertionError
test_api_flow.py::test_sensitive_interface FAILED [ 12%]
===== 测试:调用飞书敏感用户接口 =====
请求头:{'Authorization': 'Bearer 6e4f12070b924862bc037cd243afd233', 'timestamp': '1762789186', 'nonce': '26b1bfd254', 'signature': 'c940620736c1bc389c1d0e17dcc5320520c65c9bb0a46944603bacb5265cdd5b', 'X-Forwarded-For': '127.0.0.1'}
响应结果:{'detail': '服务器内部错误'}
test_api_flow.py:208 (test_sensitive_interface)
500 != 200
Expected :200
Actual :500
<Click to see difference>
def test_sensitive_interface():
"""测试调用飞书敏感接口(Token + 签名双重鉴权,正向测试)"""
# 打印测试场景描述
print(f"\n===== 测试:调用飞书敏感用户接口 =====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
access_token = get_valid_token()
# 生成签名参数(timestamp、nonce、signature)
timestamp, nonce, signature = generate_signature(credentials["appsecret"])
# 拼接敏感用户接口地址,指定user_id为200
url = f"{BASE_URL}/api/v1/user/200"
# 构造请求头,包含Token、签名参数和白名单IP
headers = {
"Authorization": f"Bearer {access_token}",
"timestamp": timestamp,
"nonce": nonce,
"signature": signature,
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求调用敏感接口
response = requests.get(url, headers=headers)
# 将响应结果转换为JSON格式
result = response.json()
# 打印调试信息,便于验证
print(f"请求头:{headers}")
print(f"响应结果:{result}")
# 断言响应状态码为200
> assert response.status_code == 200
E assert 500 == 200
E + where 500 = <Response [500]>.status_code
test_api_flow.py:240: AssertionError
test_api_flow.py::test_refresh_token FAILED [ 16%]
===== 测试:刷新飞书access_token =====
旧Token:ecb4b4f94e204ec1976e...
刷新响应:{'errcode': 0, 'errmsg': 'success', 'detail': 'access_token 已强制过期,请重新获取'}
test_api_flow.py:251 (test_refresh_token)
500 != 401
Expected :401
Actual :500
<Click to see difference>
def test_refresh_token():
"""测试刷新飞书access_token(旧Token过期,正向测试)"""
# 打印测试场景描述
print(f"\n===== 测试:刷新飞书access_token =====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 拼接Token接口地址
url = f"{BASE_URL}/api/v1/token"
# 构造请求头,包含appid和appsecret
headers = {
"X-Appid": credentials["appid"],
"X-Appsecret": credentials["appsecret"]
}
# 步骤1:获取旧Token
old_token = get_valid_token()
# 打印旧Token(脱敏显示前20位)
print(f"旧Token:{old_token[:20]}...")
# 步骤2:刷新Token(强制过期)
# 发送DELETE请求刷新Token
delete_response = requests.delete(url, headers=headers)
# 将响应结果转换为JSON格式
delete_result = delete_response.json()
# 打印刷新响应结果
print(f"刷新响应:{delete_result}")
# 断言刷新请求状态码为200
assert delete_response.status_code == 200
# 断言刷新操作错误码为0
assert delete_result["errcode"] == 0
# 步骤3:验证旧Token失效
# 拼接普通数据接口地址,用于验证Token有效性
test_url = f"{BASE_URL}/api/v1/data"
# 构造请求头,携带旧Token
test_headers = {
"Authorization": f"Bearer {old_token}",
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求,使用旧Token调用接口
invalid_response = requests.get(test_url, headers=test_headers)
# 断言响应状态码为401(未授权)
> assert invalid_response.status_code == 401
E assert 500 == 401
E + where 500 = <Response [500]>.status_code
test_api_flow.py:294: AssertionError
test_api_flow.py::test_invalid_token FAILED [ 20%]
===== 测试:无效Token调用(负例)=====
请求头:{'Authorization': 'Bearer invalid_token_123456', 'X-Forwarded-For': '127.0.0.1'}
响应结果:{'detail': '服务器内部错误'}
test_api_flow.py:317 (test_invalid_token)
500 != 401
Expected :401
Actual :500
<Click to see difference>
def test_invalid_token():
"""测试无效Token调用接口(负例测试)"""
# 打印测试场景描述
print(f"\n===== 测试:无效Token调用(负例)=====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 拼接普通数据接口地址
url = f"{BASE_URL}/api/v1/data"
# 构造请求头,携带无效Token
headers = {
"Authorization": "Bearer invalid_token_123456",
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求,使用无效Token调用接口
response = requests.get(url, headers=headers)
# 将响应结果转换为JSON格式
result = response.json()
# 打印调试信息
print(f"请求头:{headers}")
print(f"响应结果:{result}")
# 断言响应状态码为401
> assert response.status_code == 401
E assert 500 == 401
E + where 500 = <Response [500]>.status_code
test_api_flow.py:341: AssertionError
test_api_flow.py::test_invalid_signature FAILED [ 25%]
===== 测试:签名错误调用敏感接口(负例)=====
请求头:{'Authorization': 'Bearer 07816befe80045e494e82069bd3dac35', 'timestamp': '1762789186', 'nonce': 'c5f86b5347', 'signature': 'f00de9d84cb95cb2066d07bc29117e59d8d0d29a5e11085491a3e7170ba5f838', 'X-Forwarded-For': '127.0.0.1'}
响应结果:{'detail': '服务器内部错误'}
test_api_flow.py:344 (test_invalid_signature)
500 != 401
Expected :401
Actual :500
<Click to see difference>
def test_invalid_signature():
"""测试签名错误调用敏感接口(负例测试)"""
# 打印测试场景描述
print(f"\n===== 测试:签名错误调用敏感接口(负例)=====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
access_token = get_valid_token()
# 生成错误签名(使用错误的appsecret)
# 生成当前时间戳(秒级)
timestamp = str(int(time.time()))
# 生成随机串nonce
nonce = str(uuid.uuid4().hex[:10])
# 拼接错误的签名原始字符串(使用wrong_appsecret)
wrong_sign_str = f"wrong_appsecret{timestamp}{nonce}{GLOBAL_SIGN_SECRET}"
# 对错误的原始字符串进行SHA256加密,得到错误签名
wrong_signature = hashlib.sha256(wrong_sign_str.encode()).hexdigest()
# 拼接敏感用户接口地址,指定user_id为300
url = f"{BASE_URL}/api/v1/user/300"
# 构造请求头,携带有效Token和错误签名
headers = {
"Authorization": f"Bearer {access_token}",
"timestamp": timestamp,
"nonce": nonce,
"signature": wrong_signature,
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求,使用错误签名调用敏感接口
response = requests.get(url, headers=headers)
# 将响应结果转换为JSON格式
result = response.json()
# 打印调试信息
print(f"请求头:{headers}")
print(f"响应结果:{result}")
# 断言响应状态码为401
> assert response.status_code == 401
E assert 500 == 401
E + where 500 = <Response [500]>.status_code
test_api_flow.py:383: AssertionError
test_api_flow.py::test_non_whitelist_ip FAILED [ 29%]
===== 测试:非白名单IP调用(负例)=====
非白名单IP:192.168.2.2,响应:{'detail': '服务器内部错误'}
test_api_flow.py:386 (test_non_whitelist_ip)
500 != 403
Expected :403
Actual :500
<Click to see difference>
def test_non_whitelist_ip():
"""测试非白名单IP调用接口(负例测试)"""
# 打印测试场景描述
print(f"\n===== 测试:非白名单IP调用(负例)=====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
access_token = get_valid_token()
# 拼接普通数据接口地址
url = f"{BASE_URL}/api/v1/data"
# 定义一个非白名单IP地址
non_whitelist_ip = "192.168.2.2"
# 构造请求头,携带有效Token和非白名单IP
headers = {
"Authorization": f"Bearer {access_token}",
"X-Forwarded-For": non_whitelist_ip
}
# 发送GET请求,使用非白名单IP调用接口
response = requests.get(url, headers=headers)
# 将响应结果转换为JSON格式
result = response.json()
# 打印调试信息
print(f"非白名单IP:{non_whitelist_ip},响应:{result}")
# 断言响应状态码为403(禁止访问)
> assert response.status_code == 403
E assert 500 == 403
E + where 500 = <Response [500]>.status_code
test_api_flow.py:413: AssertionError
test_api_flow.py::test_bearer_format FAILED [ 33%]
===== 测试:Bearer格式错误(负例)=====
test_api_flow.py:416 (test_bearer_format)
500 != 200
Expected :200
Actual :500
<Click to see difference>
def test_bearer_format():
"""测试Bearer格式错误(负例测试)"""
# 打印测试场景描述
print(f"\n===== 测试:Bearer格式错误(负例)=====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
valid_token = get_valid_token()
# 获取白名单IP
whitelist_ip = credentials["whitelist_ip"]
# 拼接普通数据接口地址
api_url = f"{BASE_URL}/api/v1/data"
# 场景1:缺少Bearer前缀
# 构造请求头,仅包含Token(缺少Bearer前缀)
headers1 = {"Authorization": valid_token, "X-Forwarded-For": whitelist_ip}
# 发送GET请求
response1 = requests.get(api_url, headers=headers1)
# 断言响应状态码为401
assert response1.status_code == 401
# 断言响应详情包含"格式错误",验证格式校验生效
assert "格式错误" in response1.json()["detail"]
# 场景2:Bearer小写
# 构造请求头,使用小写bearer前缀
headers2 = {"Authorization": f"bearer {valid_token}", "X-Forwarded-For": whitelist_ip}
# 发送GET请求
response2 = requests.get(api_url, headers=headers2)
# 断言响应状态码为401
assert response2.status_code == 401
# 断言响应详情包含"格式错误"
assert "格式错误" in response2.json()["detail"]
# 场景3:多余冒号
# 构造请求头,使用Bearer:格式(错误分隔符)
headers3 = {"Authorization": f"Bearer:{valid_token}", "X-Forwarded-For": whitelist_ip}
# 发送GET请求
response3 = requests.get(api_url, headers=headers3)
# 断言响应状态码为401
assert response3.status_code == 401
# 断言响应详情包含"格式错误"
assert "格式错误" in response3.json()["detail"]
# 场景4:正常格式(对比验证)
# 构造请求头,使用正确的Bearer + 空格 + Token格式
headers4 = {"Authorization": f"Bearer {valid_token}", "X-Forwarded-For": whitelist_ip}
# 发送GET请求
response4 = requests.get(api_url, headers=headers4)
# 断言响应状态码为200
> assert response4.status_code == 200
E assert 500 == 200
E + where 500 = <Response [500]>.status_code
test_api_flow.py:466: AssertionError
test_api_flow.py::test_token_expiration FAILED [ 37%]
===== 测试:Token过期调用(负例)=====
过期Token调用响应:{'detail': '服务器内部错误'}
test_api_flow.py:469 (test_token_expiration)
500 != 401
Expected :401
Actual :500
<Click to see difference>
def test_token_expiration():
"""测试Token过期后调用接口(负例测试)"""
# 打印测试场景描述
print(f"\n===== 测试:Token过期调用(负例)=====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
access_token = get_valid_token()
# 手动修改Token的expire_at为当前时间-10秒(直接过期)
try:
# 连接Redis服务器
redis_client = redis.Redis(** REDIS_CONFIG)
# 新结构:token:{access_token}(对应后端重构后的存储键)
token_key = f"token:{access_token}"
# 从Redis中获取Token信息字符串
token_info_str = redis_client.get(token_key)
# 若Token信息不存在,跳过测试
if not token_info_str:
pytest.skip("Token不存在于Redis")
# 解析Token信息字符串为字典(注意:eval存在安全风险,仅测试环境使用)
token_info = eval(token_info_str)
# 修改过期时间为当前时间-10秒(已过期)
token_info["expire_at"] = time.time() - 10
# 将修改后的Token信息写回Redis
redis_client.set(token_key, str(token_info))
# 等待1秒,确保时间戳生效
time.sleep(1)
except Exception as e:
# 若修改失败,跳过测试
pytest.skip(f"修改Token过期时间失败:{e}")
# 调用接口验证过期Token
url = f"{BASE_URL}/api/v1/data"
# 构造请求头,携带已过期的Token
headers = {
"Authorization": f"Bearer {access_token}",
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求
response = requests.get(url, headers=headers)
# 将响应结果转换为JSON格式
result = response.json()
# 打印调试信息
print(f"过期Token调用响应:{result}")
# 断言响应状态码为401
> assert response.status_code == 401
E assert 500 == 401
E + where 500 = <Response [500]>.status_code
test_api_flow.py:517: AssertionError
test_api_flow.py::test_signature_expired FAILED [ 41%]
===== 测试:签名过期调用(负例)=====
过期签名调用响应:{'detail': '服务器内部错误'}
test_api_flow.py:518 (test_signature_expired)
500 != 401
Expected :401
Actual :500
<Click to see difference>
def test_signature_expired():
"""测试签名过期调用敏感接口(负例测试)"""
# 打印测试场景描述
print(f"\n===== 测试:签名过期调用(负例)=====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
access_token = get_valid_token()
# 生成过期的时间戳(当前时间-360秒,即过期6分钟)
timestamp = str(int(time.time()) - 360)
# 生成随机串nonce
nonce = str(uuid.uuid4().hex[:10])
# 拼接签名原始字符串
sign_str = f"{credentials['appsecret']}{timestamp}{nonce}{GLOBAL_SIGN_SECRET}"
# 生成签名
signature = hashlib.sha256(sign_str.encode()).hexdigest()
# 拼接敏感用户接口地址
url = f"{BASE_URL}/api/v1/user/200"
# 构造请求头,携带过期签名参数
headers = {
"Authorization": f"Bearer {access_token}",
"timestamp": timestamp,
"nonce": nonce,
"signature": signature,
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求,使用过期签名调用敏感接口
response = requests.get(url, headers=headers)
# 将响应结果转换为JSON格式
result = response.json()
# 打印调试信息
print(f"过期签名调用响应:{result}")
# 断言响应状态码为401
> assert response.status_code == 401
E assert 500 == 401
E + where 500 = <Response [500]>.status_code
test_api_flow.py:555: AssertionError
test_api_flow.py::test_missing_signature_params PASSED [ 45%]
===== 测试:缺少签名参数(负例)=====
所有缺少签名参数场景均验证通过
test_api_flow.py::test_invalid_appid_appsecret PASSED [ 50%]
===== 测试:无效凭证获取Token(负例)=====
无效凭证响应:{'detail': '无效的 X-Appid'}
test_api_flow.py::test_signature_params_tampered FAILED [ 54%]
===== 测试:签名参数被篡改(负例)=====
test_api_flow.py:627 (test_signature_params_tampered)
500 != 401
Expected :401
Actual :500
<Click to see difference>
def test_signature_params_tampered():
"""测试签名参数被篡改(timestamp/nonce/signature任一修改,负例测试)"""
# 打印测试场景描述
print(f"\n===== 测试:签名参数被篡改(负例)=====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
access_token = get_valid_token()
# 生成正确签名参数
timestamp, nonce, signature = generate_signature(credentials["appsecret"])
# 拼接敏感用户接口地址
url = f"{BASE_URL}/api/v1/user/200"
# 场景1:篡改timestamp(在正确值基础上加1)
tampered_ts = str(int(timestamp) + 1)
# 构造请求头,使用篡改后的timestamp
headers1 = {
"Authorization": f"Bearer {access_token}",
"timestamp": tampered_ts,
"nonce": nonce,
"signature": signature,
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求
response1 = requests.get(url, headers=headers1)
# 断言响应状态码为401
> assert response1.status_code == 401
E assert 500 == 401
E + where 500 = <Response [500]>.status_code
test_api_flow.py:655: AssertionError
test_api_flow.py::test_appsecret_changed_token_invalid SKIPPEDsponse
[500]>.status_code) [ 58%]
===== 测试:appsecret修改后旧Token失效 =====
Skipped: 测试需手动临时修改appsecret,跳过原因:assert 500 == 401
+ where 500 = <Response [500]>.status_code
test_api_flow.py::test_multi_appid_token_isolation SKIPPED [ 62%]
===== 测试:多appid Token缓存隔离 =====
Skipped: 请先在core/config.py中添加feishu_mock_appid_2的凭证配置
test_api_flow.py::test_cors_compatibility PASSED [ 66%]
===== 测试:跨域请求兼容性 =====
跨域请求兼容性验证通过
test_api_flow.py::test_signature_case_sensitive FAILED [ 70%]
===== 测试:签名参数大小写敏感 =====
test_api_flow.py:859 (test_signature_case_sensitive)
500 != 401
Expected :401
Actual :500
<Click to see difference>
def test_signature_case_sensitive():
"""测试签名参数大小写敏感(飞书签名大小写严格校验,负例测试)"""
# 打印测试场景描述
print(f"\n===== 测试:签名参数大小写敏感 =====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
access_token = get_valid_token()
# 生成正确签名(全小写nonce,全大写signature)
timestamp = str(int(time.time()))
nonce = str(uuid.uuid4().hex[:10]).lower()
# 拼接签名原始字符串
sign_str = f"{credentials['appsecret']}{timestamp}{nonce}{GLOBAL_SIGN_SECRET}"
# 生成签名并转为大写
signature = hashlib.sha256(sign_str.encode()).hexdigest().upper()
# 拼接敏感用户接口地址
url = f"{BASE_URL}/api/v1/user/200"
# 构造请求头,将nonce转为大写、signature转为小写(与生成时不一致)
headers = {
"Authorization": f"Bearer {access_token}",
"timestamp": timestamp,
"nonce": nonce.upper(), # nonce大写(与签名时的小写不一致)
"signature": signature.lower(), # signature小写(与生成时的大写不一致)
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求
response = requests.get(url, headers=headers)
# 断言响应状态码为401
> assert response.status_code == 401
E assert 500 == 401
E + where 500 = <Response [500]>.status_code
test_api_flow.py:890: AssertionError
test_api_flow.py::test_invalid_token_length FAILED [ 75%]
===== 测试:非法长度Token =====
test_api_flow.py:895 (test_invalid_token_length)
500 != 401
Expected :401
Actual :500
<Click to see difference>
def test_invalid_token_length():
"""测试非法长度Token(飞书Token为32位,验证边界,负例测试)"""
# 打印测试场景描述
print(f"\n===== 测试:非法长度Token =====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 拼接普通数据接口地址
url = f"{BASE_URL}/api/v1/data"
# 场景1:Token过短(10位)
short_token = "short123456"
# 构造请求头,携带过短Token
headers1 = {
"Authorization": f"Bearer {short_token}",
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求
response1 = requests.get(url, headers=headers1)
# 断言响应状态码为401
> assert response1.status_code == 401
E assert 500 == 401
E + where 500 = <Response [500]>.status_code
test_api_flow.py:914: AssertionError
test_api_flow.py::test_reused_signature FAILED [ 79%]
===== 测试:签名重复使用 =====
test_api_flow.py:929 (test_reused_signature)
500 != 200
Expected :200
Actual :500
<Click to see difference>
def test_reused_signature():
"""测试敏感接口签名重复使用(根据后端实际是否实现防重放机制调整,负例测试)"""
# 打印测试场景描述
print(f"\n===== 测试:签名重复使用 =====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
access_token = get_valid_token()
# 生成一组签名并首次使用(有效)
timestamp, nonce, signature = generate_signature(credentials["appsecret"])
# 拼接敏感用户接口地址
url = f"{BASE_URL}/api/v1/user/200"
# 构造请求头,包含签名参数
headers = {
"Authorization": f"Bearer {access_token}",
"timestamp": timestamp,
"nonce": nonce,
"signature": signature,
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 首次调用(有效)
response1 = requests.get(url, headers=headers)
# 断言首次调用成功(状态码200)
> assert response1.status_code == 200
E assert 500 == 200
E + where 500 = <Response [500]>.status_code
test_api_flow.py:954: AssertionError
test_api_flow.py::test_token_concurrent_use FAILED [ 83%]
===== 测试:Token并发调用 =====
test_api_flow.py:968 (test_token_concurrent_use)
0 != 5
Expected :5
Actual :0
<Click to see difference>
def test_token_concurrent_use():
"""测试Token并发调用接口(飞书Token支持多线程并发使用,正向测试)"""
# 打印测试场景描述
print(f"\n===== 测试:Token并发调用 =====")
# 获取主应用的凭证信息
credentials = TEST_CREDENTIALS["feishu"]
# 获取有效access_token
access_token = get_valid_token()
# 拼接普通数据接口地址
url = f"{BASE_URL}/api/v1/data/100"
# 成功调用计数
success_count = 0
# 总线程数
total_threads = 5
# 定义线程执行的函数:调用接口并统计成功次数
def call_api():
# 使用nonlocal关键字引用外部函数的变量
nonlocal success_count
# 构造请求头
headers = {
"Authorization": f"Bearer {access_token}",
"X-Forwarded-For": credentials["whitelist_ip"]
}
# 发送GET请求
response = requests.get(url, headers=headers)
# 若响应成功(状态码200且错误码0),成功计数+1
if response.status_code == 200 and response.json()["errcode"] == 0:
success_count += 1
# 创建5个线程,目标函数为call_api
threads = [threading.Thread(target=call_api) for _ in range(total_threads)]
# 启动所有线程
for t in threads:
t.start()
# 等待所有线程执行完毕
for t in threads:
t.join()
# 断言所有线程调用成功
> assert success_count == total_threads
E assert 0 == 5
test_api_flow.py:1009: AssertionError
test_api_flow.py::test_sensitive_post_with_body FAILED [ 87%]
===== 测试:敏感接口POST请求 - body参与签名(正向)=====
test_api_flow.py:1017 (test_sensitive_post_with_body)
def test_sensitive_post_with_body():
"""测试敏感接口POST请求且body参与签名(正向测试)"""
print(f"\n===== 测试:敏感接口POST请求 - body参与签名(正向)=====")
credentials = TEST_CREDENTIALS["feishu"]
access_token = get_valid_token()
# 准备请求体数据(注意:JSON序列化格式需一致,避免空格影响)
payload = {"user_id": 100, "action": "update_profile"}
# JSON dumps 使用 separators 确保无多余空格,防止签名不一致
> body_str = json.dumps(payload, separators=(',', ':'))
E NameError: name 'json' is not defined
test_api_flow.py:1027: NameError
test_api_flow.py::test_sensitive_post_body_tampered FAILED [ 91%]
===== 测试:敏感接口POST请求 - body被篡改(负例)=====
test_api_flow.py:1059 (test_sensitive_post_body_tampered)
def test_sensitive_post_body_tampered():
"""测试敏感接口POST请求但body被篡改(负例测试)"""
print(f"\n===== 测试:敏感接口POST请求 - body被篡改(负例)=====")
credentials = TEST_CREDENTIALS["feishu"]
access_token = get_valid_token()
# 正常请求体
original_payload = {"user_id": 200, "action": "delete_account"}
> original_body = json.dumps(original_payload, separators=(',', ':'))
E NameError: name 'json' is not defined
test_api_flow.py:1068: NameError
test_api_flow.py::test_sensitive_post_body_order_sensitive FAILED [ 95%]
===== 测试:JSON字段顺序不同导致签名失效 =====
test_api_flow.py:1100 (test_sensitive_post_body_order_sensitive)
def test_sensitive_post_body_order_sensitive():
"""测试JSON字段顺序不同导致签名不一致(典型坑点)"""
print(f"\n===== 测试:JSON字段顺序不同导致签名失效 =====")
credentials = TEST_CREDENTIALS["feishu"]
access_token = get_valid_token()
# 字段顺序不同但语义相同
payload1 = {"action": "login", "user_id": 999}
payload2 = {"user_id": 999, "action": "login"}
> body1 = json.dumps(payload1, separators=(',', ':')) # action 在前
E NameError: name 'json' is not defined
test_api_flow.py:1111: NameError
test_api_flow.py::test_sensitive_post_missing_body_in_sign FAILED [100%]
===== 测试:签名未包含body但请求带有body(绕过检测?)=====
test_api_flow.py:1148 (test_sensitive_post_missing_body_in_sign)
def test_sensitive_post_missing_body_in_sign():
"""测试签名未包含body但实际有body(安全漏洞模拟)"""
print(f"\n===== 测试:签名未包含body但请求带有body(绕过检测?)=====")
credentials = TEST_CREDENTIALS["feishu"]
access_token = get_valid_token()
payload = {"risk": "high"}
> body = json.dumps(payload, separators=(',', ':'))
E NameError: name 'json' is not defined
test_api_flow.py:1156: NameError
=================== 18 failed, 4 passed, 2 skipped in 2.06s ===================
Process finished with exit code 1
最新发布