From 61eb4341387a6a32f0d98ab5a447bd06bfaa55bf Mon Sep 17 00:00:00 2001 From: yml2213 Date: Tue, 1 Sep 2026 23:15:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=8C=E4=BB=BDcookie=E5=AD=98=E5=82=A8?= =?UTF-8?q?=EF=BC=9Araw=5Fcookie=20=E4=BF=9D=E5=AD=98App=E5=8E=9F=E5=A7=8B?= =?UTF-8?q?=E5=87=AD=E6=8D=AE=EF=BC=8C=E4=B8=8E=E7=BD=91=E9=A1=B5=E8=BF=90?= =?UTF-8?q?=E8=A1=8Cck=E5=88=86=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 网页运行ck(cookie列)含本地随机生成的网页设备字段,若被风控标记 无法还原纯净登录凭据;新增 raw_cookie 保存16字段App原始态,供 设备态重建/审计/复核登录有效性。 - HuyaAccount 加 raw_cookie 列(alembic 0034,MySQL TEXT nullable) - HuyaLoginResult 加 raw_cookie 字段;App登录链补齐前快照原始凭据 - upsert_huya_cookie 支持双写;app-password-login 路由透传 raw_cookie - 存量行 raw_cookie 为 NULL(老账号无快照),新登录自动填充 --- core/huya/app_login.py | 2 + core/huya/login.py | 1 + tests/test_migrations.py | 2 +- .../20260901_0034_huya_accounts_raw_cookie.py | 40 +++++++++++++++++++ web/backend/models.py | 4 ++ web/backend/routers/huya.py | 6 ++- web/backend/services/huya_service.py | 15 ++++++- 7 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 web/backend/migrations/versions/20260901_0034_huya_accounts_raw_cookie.py diff --git a/core/huya/app_login.py b/core/huya/app_login.py index bcaa1d9..9df356c 100644 --- a/core/huya/app_login.py +++ b/core/huya/app_login.py @@ -833,6 +833,7 @@ class HuyaAppPasswordLogin: code="COOKIE_INCOMPLETE", ) + raw_cookie_str = cookie_str # 补齐前 = App 原始登录凭据(16 字段 udb_*) # 补齐网页设备字段并修正 appId:真实网页登录态是 41 字段 + # udb_appid=5002,App 扫码链只产出 16 个 udb_* 认证字段且 appId=5008 # (App 渠道),缺字段注入浏览器会导致 UDB SDK 判定设备态不完整。 @@ -857,6 +858,7 @@ class HuyaAppPasswordLogin: return HuyaLoginResult( success=True, cookie=cookie_str, + raw_cookie=raw_cookie_str, message="App协议登录成功", sdid=sdid, context=pc.context, diff --git a/core/huya/login.py b/core/huya/login.py index 7edb24e..1094f2c 100644 --- a/core/huya/login.py +++ b/core/huya/login.py @@ -62,6 +62,7 @@ class HuyaLoginResult: success: bool cookie: str = "" + raw_cookie: str = "" # App 原始登录凭据(不含网页设备字段),用于设备态重建/审计 message: str = "" code: int | str = "" raw: dict | None = None diff --git a/tests/test_migrations.py b/tests/test_migrations.py index 61592c9..cdeb8da 100644 --- a/tests/test_migrations.py +++ b/tests/test_migrations.py @@ -22,7 +22,7 @@ TESTS_DIR = Path(__file__).resolve().parent PROJECT_ROOT = TESTS_DIR.parent VERSIONS_DIR = PROJECT_ROOT / "web" / "backend" / "migrations" / "versions" -HEAD_REVISION = "20260901_0033" +HEAD_REVISION = "20260901_0034" # 迁移新增、但不声明在模型里的复合查询索引。 EXTRA_INDEXES = ( diff --git a/web/backend/migrations/versions/20260901_0034_huya_accounts_raw_cookie.py b/web/backend/migrations/versions/20260901_0034_huya_accounts_raw_cookie.py new file mode 100644 index 0000000..778dacd --- /dev/null +++ b/web/backend/migrations/versions/20260901_0034_huya_accounts_raw_cookie.py @@ -0,0 +1,40 @@ +"""huya_accounts 增加 raw_cookie:保存 App 登录原始凭据(与网页运行 ck 分离)。 + +网页运行 ck(cookie 列)含本地随机生成的网页设备字段(guid/_qimei_uuid42/ +__yamid_new/game_did),若设备字段被风控标记无法还原纯净的登录凭据。 +raw_cookie 保存 16 字段的原始 App 登录态(udb_* 认证 + sdid/hdid + 匿名设备 +字段),用于重建设备态/审计/复核登录有效性。 +""" + +from collections.abc import Sequence + +import sqlalchemy as sa +from alembic import op + +revision: str = "20260901_0034" +down_revision: str | None = "20260901_0033" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +def upgrade() -> None: + bind = op.get_bind() + columns = { + item["name"] for item in sa.inspect(bind).get_columns("huya_accounts") + } + if "raw_cookie" not in columns: + # MySQL 的 TEXT 列不允许 server_default;模型层 default="" 负责新行, + # 存量行为 NULL(读取处按空处理)。 + op.add_column( + "huya_accounts", + sa.Column("raw_cookie", sa.Text(), nullable=True), + ) + + +def downgrade() -> None: + bind = op.get_bind() + columns = { + item["name"] for item in sa.inspect(bind).get_columns("huya_accounts") + } + if "raw_cookie" in columns: + op.drop_column("huya_accounts", "raw_cookie") \ No newline at end of file diff --git a/web/backend/models.py b/web/backend/models.py index 96bd7dd..499c7f0 100644 --- a/web/backend/models.py +++ b/web/backend/models.py @@ -369,6 +369,10 @@ class HuyaAccount(Base): account_password: Mapped[str] = mapped_column(EncryptedText(), default="") nickname: Mapped[str] = mapped_column(String(128), default="") cookie: Mapped[str] = mapped_column(EncryptedText(), nullable=False) + # App 登录原始凭据(16 字段 udb_*,不含本地随机生成的网页设备字段)。 + # 网页运行 ck(cookie 列)含 guid/_qimei_uuid42 等设备快照,若被风控标记 + # 可从 raw_cookie 重建;也用于审计/复核登录有效性。 + raw_cookie: Mapped[str] = mapped_column(EncryptedText(), nullable=False, default="") tag: Mapped[str] = mapped_column(String(64), default="") remark: Mapped[str] = mapped_column(String(256), default="") status: Mapped[str] = mapped_column(String(32), default="imported") diff --git a/web/backend/routers/huya.py b/web/backend/routers/huya.py index 6f38675..4256781 100644 --- a/web/backend/routers/huya.py +++ b/web/backend/routers/huya.py @@ -695,7 +695,11 @@ def app_password_login_account( try: account = upsert_huya_cookie( - db, result.cookie, tag=req.tag, username_hint=req.username + db, + result.cookie, + tag=req.tag, + username_hint=req.username, + raw_cookie=getattr(result, "raw_cookie", ""), ) if hasattr(account, "account_password") and req.password: account.account_password = req.password diff --git a/web/backend/services/huya_service.py b/web/backend/services/huya_service.py index dd939ac..f75d3fa 100644 --- a/web/backend/services/huya_service.py +++ b/web/backend/services/huya_service.py @@ -303,9 +303,18 @@ def save_huya_login_cookie_to_account( def upsert_huya_cookie( - db: Session, cookie: str, tag: str = "", username_hint: str = "" + db: Session, + cookie: str, + tag: str = "", + username_hint: str = "", + raw_cookie: str = "", ) -> HuyaAccount: - """保存单条登录得到的虎牙 Cookie。""" + """保存单条登录得到的虎牙 Cookie。 + + Args: + cookie: 网页运行 Cookie(可能含本地生成的网页设备字段)。 + raw_cookie: App 原始登录凭据(不含网页设备字段),单独落库供重建/审计。 + """ line = f"{username_hint}----{cookie}" if username_hint else cookie parsed = parse_huya_cookie_line(line) if not parsed: @@ -313,6 +322,8 @@ def upsert_huya_cookie( account = _upsert_huya_account( db, parsed, tag=(tag or "").strip(), status="login_success" ) + if raw_cookie: + account.raw_cookie = normalize_huya_cookie(raw_cookie) db.commit() db.refresh(account) return account