双份cookie存储:raw_cookie 保存App原始凭据,与网页运行ck分离
网页运行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(老账号无快照),新登录自动填充
This commit is contained in:
@@ -833,6 +833,7 @@ class HuyaAppPasswordLogin:
|
|||||||
code="COOKIE_INCOMPLETE",
|
code="COOKIE_INCOMPLETE",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
raw_cookie_str = cookie_str # 补齐前 = App 原始登录凭据(16 字段 udb_*)
|
||||||
# 补齐网页设备字段并修正 appId:真实网页登录态是 41 字段 +
|
# 补齐网页设备字段并修正 appId:真实网页登录态是 41 字段 +
|
||||||
# udb_appid=5002,App 扫码链只产出 16 个 udb_* 认证字段且 appId=5008
|
# udb_appid=5002,App 扫码链只产出 16 个 udb_* 认证字段且 appId=5008
|
||||||
# (App 渠道),缺字段注入浏览器会导致 UDB SDK 判定设备态不完整。
|
# (App 渠道),缺字段注入浏览器会导致 UDB SDK 判定设备态不完整。
|
||||||
@@ -857,6 +858,7 @@ class HuyaAppPasswordLogin:
|
|||||||
return HuyaLoginResult(
|
return HuyaLoginResult(
|
||||||
success=True,
|
success=True,
|
||||||
cookie=cookie_str,
|
cookie=cookie_str,
|
||||||
|
raw_cookie=raw_cookie_str,
|
||||||
message="App协议登录成功",
|
message="App协议登录成功",
|
||||||
sdid=sdid,
|
sdid=sdid,
|
||||||
context=pc.context,
|
context=pc.context,
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class HuyaLoginResult:
|
|||||||
|
|
||||||
success: bool
|
success: bool
|
||||||
cookie: str = ""
|
cookie: str = ""
|
||||||
|
raw_cookie: str = "" # App 原始登录凭据(不含网页设备字段),用于设备态重建/审计
|
||||||
message: str = ""
|
message: str = ""
|
||||||
code: int | str = ""
|
code: int | str = ""
|
||||||
raw: dict | None = None
|
raw: dict | None = None
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ TESTS_DIR = Path(__file__).resolve().parent
|
|||||||
PROJECT_ROOT = TESTS_DIR.parent
|
PROJECT_ROOT = TESTS_DIR.parent
|
||||||
VERSIONS_DIR = PROJECT_ROOT / "web" / "backend" / "migrations" / "versions"
|
VERSIONS_DIR = PROJECT_ROOT / "web" / "backend" / "migrations" / "versions"
|
||||||
|
|
||||||
HEAD_REVISION = "20260901_0033"
|
HEAD_REVISION = "20260901_0034"
|
||||||
|
|
||||||
# 迁移新增、但不声明在模型里的复合查询索引。
|
# 迁移新增、但不声明在模型里的复合查询索引。
|
||||||
EXTRA_INDEXES = (
|
EXTRA_INDEXES = (
|
||||||
|
|||||||
@@ -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")
|
||||||
@@ -369,6 +369,10 @@ class HuyaAccount(Base):
|
|||||||
account_password: Mapped[str] = mapped_column(EncryptedText(), default="")
|
account_password: Mapped[str] = mapped_column(EncryptedText(), default="")
|
||||||
nickname: Mapped[str] = mapped_column(String(128), default="")
|
nickname: Mapped[str] = mapped_column(String(128), default="")
|
||||||
cookie: Mapped[str] = mapped_column(EncryptedText(), nullable=False)
|
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="")
|
tag: Mapped[str] = mapped_column(String(64), default="")
|
||||||
remark: Mapped[str] = mapped_column(String(256), default="")
|
remark: Mapped[str] = mapped_column(String(256), default="")
|
||||||
status: Mapped[str] = mapped_column(String(32), default="imported")
|
status: Mapped[str] = mapped_column(String(32), default="imported")
|
||||||
|
|||||||
@@ -695,7 +695,11 @@ def app_password_login_account(
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
account = upsert_huya_cookie(
|
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:
|
if hasattr(account, "account_password") and req.password:
|
||||||
account.account_password = req.password
|
account.account_password = req.password
|
||||||
|
|||||||
@@ -303,9 +303,18 @@ def save_huya_login_cookie_to_account(
|
|||||||
|
|
||||||
|
|
||||||
def upsert_huya_cookie(
|
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:
|
) -> HuyaAccount:
|
||||||
"""保存单条登录得到的虎牙 Cookie。"""
|
"""保存单条登录得到的虎牙 Cookie。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cookie: 网页运行 Cookie(可能含本地生成的网页设备字段)。
|
||||||
|
raw_cookie: App 原始登录凭据(不含网页设备字段),单独落库供重建/审计。
|
||||||
|
"""
|
||||||
line = f"{username_hint}----{cookie}" if username_hint else cookie
|
line = f"{username_hint}----{cookie}" if username_hint else cookie
|
||||||
parsed = parse_huya_cookie_line(line)
|
parsed = parse_huya_cookie_line(line)
|
||||||
if not parsed:
|
if not parsed:
|
||||||
@@ -313,6 +322,8 @@ def upsert_huya_cookie(
|
|||||||
account = _upsert_huya_account(
|
account = _upsert_huya_account(
|
||||||
db, parsed, tag=(tag or "").strip(), status="login_success"
|
db, parsed, tag=(tag or "").strip(), status="login_success"
|
||||||
)
|
)
|
||||||
|
if raw_cookie:
|
||||||
|
account.raw_cookie = normalize_huya_cookie(raw_cookie)
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(account)
|
db.refresh(account)
|
||||||
return account
|
return account
|
||||||
|
|||||||
Reference in New Issue
Block a user