账号ID 151
签名密钥skey test
签名密钥skey 在设置中心查看
运行命令: python login.py --uid 151 --skey test
#!/usr/bin/env python3
-- coding: utf-8 --
"""
自动生成签名并调用登录接口。
- 首次使用本机时间生成 sign。
- 如果返回“参数time和服务器时间相差不能超过60秒, 当前服务器时间为[...]”,自动解析[]中的服务器时间,
重新计算 sign 并重试一次。
使用方法:
python login.py --uid 151 --skey test
"""
import time
import random
import string
import hashlib
import argparse
import json
import re
from typing import Optional, Dict, Any
import requests
def md5(data: str) -> str:
return hashlib.md5(data.encode("utf-8")).hexdigest()
def generate_auth_params(uid: int, skey: str, ts: Optional[int] = None, rand: Optional[str] = None) -> Dict[str, Any]:
"""
生成登录所需参数(time / rand / sign / uid)
签名:sign = md5(md5(md5(md5(skey) + rand)) + time)
"""
if ts is None:
ts = int(time.time())
if rand is None:
rand = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
layer1 = md5(skey)
layer2 = md5(layer1 + rand)
layer3 = md5(layer2)
sign = md5(layer3 + str(ts))
return {"uid": uid, "time": ts, "rand": rand, "sign": sign}
def call_login(url: str, payload: dict, timeout: int = 10):
"""
请求登录接口。这里改为 application/x-www-form-urlencoded。
"""
headers = {"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"}
return requests.post(url, data=payload, headers=headers, timeout=timeout)
def try_login(url: str, uid: int, skey: str, ts: Optional[int], timeout: int = 10) -> None:
# 第一次:用给定 ts(或本机时间)
params = generate_auth_params(uid, skey, ts=ts)
print("===> 第一次尝试:payload")
print(json.dumps(params, ensure_ascii=False, indent=2))
resp = call_login(url, params, timeout=timeout)
print(f"HTTP {resp.status_code}")
text = resp.text
print(text)
# 若时间漂移导致失败,且响应中包含服务器时间,则解析后重试一次
# 兼容两种常见提示:
# 参数time和服务器时间相差不能超过60秒,当前服务器时间为[1759127337]
# 参数time和服务器时间相差不能超过60秒, 当前服务器时间为 [1759127337]
m = re.search(r"服务器时间为\s*\[\s*(\d{10})\s*\]", text)
if m:
server_ts = int(m.group(1))
print(f"检测到服务器时间:{server_ts},将使用该时间重试一次...")
# 使用同一个 rand 更可追踪,也可重新生成;这里复用 rand:
rand = params["rand"]
retry_params = generate_auth_params(uid, skey, ts=server_ts, rand=rand)
print('===> 第二次尝试(使用服务器时间):payload')
print(json.dumps(retry_params, ensure_ascii=False, indent=2))
resp2 = call_login(url, retry_params, timeout=timeout)
print(f"HTTP {resp2.status_code}")
print(resp2.text)
def main():
parser = argparse.ArgumentParser(description="生成 sign 并调用登录 API")
parser.add_argument("--uid", type=int, required=True, help="账号ID")
parser.add_argument("--skey", type=str, required=True, help="签名密钥 skey")
parser.add_argument("--url", type=str, default="https://open.aaacdn.cn/api/auth/login", help="登录接口URL")
parser.add_argument("--time", type=int, default=None, help="可选:指定10位时间戳(默认使用本机当前时间)")
parser.add_argument("--timeout", type=int, default=10, help="请求超时时间(秒)")
args = parser.parse_args()
try_login(args.url, args.uid, args.skey, args.time, timeout=args.timeout)
if __name__ == "__main__":
main()