feat: session login + authed client
Task 1.4 — 会话层. Adds the authenticated HTTP client that every yunke scraper will use to call the CRM API. - app/session/login.py: get_secure_key + pc_login wrappers, LoginResult dataclass, and a clearly-marked Phase-0 swappable encrypt_password placeholder (real RSA per getSecureKey is a TODO; drop-in contract documented in the docstring). - app/session/yunke_client.py: YunkeClient wrapping httpx.AsyncClient. Constructor takes either (username+password) for auto-login or (userid+company[+cookies]) for an existing session. Injects the 5 observed auth headers (userid/company/source=yunkepc/channel=4/ content-type=application/json) on every request, auto-logs-in on first request, and on HTTP 401 (or body code 401) re-logs-in once and retries — a persistent 401 raises after the single retry so there is no infinite loop. - Tests (respx): login populates LoginResult + httpx cookie jar; every request carries all 5 auth headers + cookie; 401 triggers exactly one re-login + retry and returns 200; persistent 401 raises after one retry; first request with no session auto-logs-in. Session is held in-memory only for now; persistence to encrypted YkAccount.session_blob_enc is left as a later concern (TODO in yunke_client.py). Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
"""会话层 (session layer) for the yunke CRM API.
|
||||
|
||||
Public surface:
|
||||
|
||||
* :class:`app.session.login.LoginResult` — parsed login outcome (userid,
|
||||
company, cookies snapshot, raw payload).
|
||||
* :func:`app.session.login.get_secure_key` — ``GET /newuc/login/getSecureKey``.
|
||||
* :func:`app.session.login.pc_login` — ``POST /usercenter/login/pcLogin``.
|
||||
* :func:`app.session.login.encrypt_password` — Phase-0 swappable password
|
||||
encryption (see file for the open TODO).
|
||||
* :class:`app.session.yunke_client.YunkeClient` — the authenticated HTTP
|
||||
client every scraper uses.
|
||||
"""
|
||||
|
||||
from app.session.login import (
|
||||
LoginResult,
|
||||
encrypt_password,
|
||||
get_secure_key,
|
||||
pc_login,
|
||||
)
|
||||
from app.session.yunke_client import YunkeClient
|
||||
|
||||
__all__ = [
|
||||
"LoginResult",
|
||||
"YunkeClient",
|
||||
"encrypt_password",
|
||||
"get_secure_key",
|
||||
"pc_login",
|
||||
]
|
||||
Reference in New Issue
Block a user