Files
yunke/yunke-server/app/session/__init__.py
T
浅念 8243e9c6d2 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>
2026-08-01 11:22:47 +08:00

30 lines
846 B
Python

"""会话层 (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",
]