更新时间:2025-10-21 10:35:03

文档内容

账号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()