共计 2006 个字符,预计需要花费 6 分钟才能阅读完成。
问题背景
最近在对接 Claude API 和 DeepSeek 服务时,遇到了强制登录验证的问题。这个问题在构建自动化流程时尤为突出,因为每次调用 API 都需要人工介入进行登录验证,严重影响了自动化效率。

通过 Wireshark 抓包分析,我们发现整个认证流程如下:
- 客户端发起 API 请求
- 服务端返回 302 重定向到登录页面
- 客户端需要完成登录流程获取会话 cookie
- 携带有效 cookie 重新发起原始请求
这种设计虽然提高了安全性,但对自动化流程造成了以下影响:
- 无法实现完全无人值守的 API 调用
- 增加了系统复杂度,需要处理会话状态
- 面临会话过期的风险,需要额外维护
技术方案对比
经过实践测试,我们总结了三种可行的解决方案:
方案 A:使用长期有效的 API Token
这是最理想的解决方案,前提是服务提供商支持。通过 JWT 生成长期有效的访问令牌:
import jwt
import datetime
def generate_jwt(secret_key, user_id):
payload = {
'user_id': user_id,
'exp': datetime.datetime.utcnow() + datetime.timedelta(days=30),
'iat': datetime.datetime.utcnow()}
return jwt.encode(payload, secret_key, algorithm='HS256')
方案 B:模拟登录会话
当无法获取长期令牌时,可以模拟浏览器登录流程:
- 使用 selenium 或 requests 模拟登录
- 获取并保存会话 cookie
- 在后续请求中携带有效 cookie
⚠️ 注意:需要处理 cookie 过期和重新登录的逻辑。
方案 C:中间层代理服务
架构图:
[Client] -> [Proxy] -> [Auth Service] -> [API]
代理服务负责:
- 维护有效会话
- 处理认证失败重试
- 缓存 API 响应
核心代码实现
以下是使用 requests.Session 保持会话的示例:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
class APIClient:
def __init__(self, base_url):
self.session = requests.Session()
# 配置重试策略
retries = Retry(
total=3,
backoff_factor=1,
status_forcelist=[401, 429, 500, 502, 503, 504]
)
self.session.mount('https://', HTTPAdapter(max_retries=retries))
# ⚠️ 从安全存储加载凭证
self.credentials = self._load_credentials()
def _load_credentials(self):
# 这里应该是从安全存储加载凭证的逻辑
# 示例中使用环境变量,生产环境建议使用 Vault 等专用系统
return {'username': os.getenv('API_USER'),
'password': os.getenv('API_PASS')
}
def login(self):
try:
response = self.session.post(f"{self.base_url}/login",
json=self.credentials,
timeout=10
)
response.raise_for_status()
return True
except requests.exceptions.RequestException as e:
print(f"登录失败: {e}")
return False
生产环境考量
速率限制规避策略
- 实现指数退避重试机制
- 监控 429 状态码频率
- 考虑分布式环境下的全局限速
凭证轮换自动化方案
- 使用短期有效的 JWT 令牌
- 自动检测令牌过期时间
- 预先刷新即将过期的令牌
审计日志必备字段
- 请求时间戳
- 调用方标识
- 请求参数摘要
- 响应状态码
- 处理时长
避坑指南
避免硬编码凭证的 3 种替代方案
- 使用环境变量
- 配置中心动态获取
- 硬件安全模块 (HSM)
正确处理 SSL 证书验证
# 生产环境应该保持验证
requests.get(url, verify=True)
# 仅测试环境可以临时关闭
requests.get(url, verify=False) # ⚠️ 不安全
会话保持的 TTL 设置建议
- 根据业务场景平衡安全性和可用性
- 典型值:15-30 分钟
- 实现自动续期机制
结语
在实际项目中,我们最终采用了方案 A 和方案 C 的组合,既保证了安全性又不失灵活性。但这也引发了两个值得思考的问题:
- 如何在提高安全门槛的同时,不影响开发者体验?
- 对于内部系统间的 API 调用,是否有必要保持同样的认证强度?
这些问题没有标准答案,需要根据具体业务场景来权衡。希望本文的分享能帮助你在类似项目中少走弯路。
正文完
