This commit is contained in:
mzl
2026-01-12 17:33:06 +08:00
parent fd467d9f60
commit 950c61226d
3 changed files with 295 additions and 53 deletions
+195 -52
View File
@@ -527,93 +527,236 @@ async def check_login_status():
async def verify_login():
"""验证登录状态"""
try:
# 直接检查浏览器中的cookie
print("[DEBUG] 开始验证登录状态...")
# 首先尝试保存 storage_state
if app_state.browser and app_state.browser.context:
try:
# 创建 storage_state 文件
storage_file = os.path.join(config.DATA_DIR, "storage_state.json")
print(f"[DEBUG] 尝试保存 storage_state 到: {storage_file}")
await app_state.browser.context.storage_state(path=storage_file)
print(f"[DEBUG] ✓ 成功保存 storage_state: {storage_file}")
# 检查文件是否存在和大小
if os.path.exists(storage_file):
size = os.path.getsize(storage_file)
print(f"[DEBUG] storage_state 文件大小: {size} bytes")
if size > 0:
# 使用 storage_state 验证登录
print("[DEBUG] 使用 storage_state 验证登录...")
return await verify_login_with_storage(storage_file)
else:
print("[DEBUG] storage_state 文件为空")
else:
print("[DEBUG] storage_state 文件未创建")
except Exception as e:
print(f"[DEBUG] ✗ 保存 storage_state 失败: {str(e)}")
pass
# 如果保存失败,尝试直接检查 cookies
print("[DEBUG] 尝试直接检查 cookies...")
if app_state.browser:
try:
# 获取所有cookies
cookies = await app_state.browser.context.cookies()
print(f"[DEBUG] 找到 {len(cookies)} 个cookies")
# 检查是否有小红书的session cookie
# 打印所有 cookies 用于调试
for cookie in cookies:
cookie_name = cookie.get('name', '')
cookie_value = cookie.get('value', '')[:20] if cookie.get('value') else ''
print(f"[DEBUG] Cookie: {cookie_name} = {cookie_value}...")
# 检查是否有登录相关的 cookie
session_cookies = []
for cookie in cookies:
cookie_name = cookie.get('name', '').lower()
cookie_value = cookie.get('value', '')
print(f"[DEBUG] Cookie: {cookie_name} = {cookie_value[:20] if cookie_value else 'EMPTY'}")
if any(keyword in cookie_name for keyword in ['session', 'token', 'login', 'auth']) and cookie_value:
if any(keyword in cookie_name for keyword in ['session', 'token', 'auth', 'passport', 'sid']):
session_cookies.append(cookie)
print(f"[DEBUG] 找到session cookie: {cookie_name}")
print(f"[DEBUG] ✓ 找到登录cookie: {cookie_name}")
if session_cookies:
# 创建本地状态文件
auth_file = os.path.join(config.DATA_DIR, "auth_state.json")
auth_data = {
"login_time": datetime.now().isoformat(),
"expire_time": (datetime.now() + timedelta(hours=24)).isoformat()
}
with open(auth_file, 'w', encoding='utf-8') as f:
json.dump(auth_data, f, ensure_ascii=False, indent=2)
# 创建 auth_state 文件
auth_file = os.path.join(config.DATA_DIR, "auth_state.json")
auth_data = {
"login_time": datetime.now().isoformat(),
"expire_time": (datetime.now() + timedelta(hours=24)).isoformat()
}
with open(auth_file, 'w', encoding='utf-8') as f:
json.dump(auth_data, f, ensure_ascii=False, indent=2)
return {
"success": True,
"message": "登录成功",
"logged_in": True,
"login_time": auth_data["login_time"],
"expire_time": auth_data["expire_time"],
"expire_in_hours": 24
}
else:
print("[DEBUG] 未找到任何session cookies")
print("[DEBUG] ✓ 创建 auth_state 文件成功")
return {
"success": True,
"message": "登录成功",
"logged_in": True,
"login_time": auth_data["login_time"],
"expire_time": auth_data["expire_time"],
"expire_in_hours": 24
}
if not session_cookies:
print("[DEBUG] ✗ 未找到登录相关的 cookies")
except Exception as e:
print(f"[DEBUG] 浏览器cookie检查失败: {str(e)}")
print(f"[DEBUG] ✗ 检查cookies失败: {str(e)}")
pass
# 检查本地登录状态文件
print("[DEBUG] 检查本地登录状态文件...")
auth_file = os.path.join(config.DATA_DIR, "auth_state.json")
if os.path.exists(auth_file):
with open(auth_file, 'r', encoding='utf-8') as f:
auth_data = json.load(f)
try:
with open(auth_file, 'r', encoding='utf-8') as f:
auth_data = json.load(f)
print(f"[DEBUG] ✓ 找到本地 auth_state 文件: {auth_data}")
# 检查登录是否过期
login_time = auth_data.get("login_time")
expire_time = auth_data.get("expire_time")
current_time = datetime.now().isoformat()
# 检查登录是否过期
login_time = auth_data.get("login_time")
expire_time = auth_data.get("expire_time")
current_time = datetime.now().isoformat()
if expire_time and current_time > expire_time:
# 登录已过期,清除状态
os.remove(auth_file)
if expire_time and current_time > expire_time:
# 登录已过期,清除状态
print("[DEBUG] ✗ 登录已过期")
os.remove(auth_file)
return {
"success": False,
"message": "登录已过期,请重新登录"
}
print("[DEBUG] ✓ 本地登录状态有效")
return {
"success": False,
"message": "登录已过期,请重新登录"
"success": True,
"message": "登录成功",
"logged_in": True,
"login_time": login_time,
"expire_time": expire_time,
"expire_in_hours": 24
}
except Exception as e:
print(f"[DEBUG] ✗ 读取 auth_state 文件失败: {str(e)}")
return {
"success": True,
"message": "登录成功",
"logged_in": True,
"login_time": login_time,
"expire_time": expire_time,
"expire_in_hours": 24
}
print("[DEBUG] 所有检查都失败了")
print("[DEBUG] ✗ 未找到任何登录状态")
return {
"success": False,
"message": "未找到登录状态,请先登录"
}
except Exception as e:
print(f"[DEBUG] 验证登录异常: {str(e)}")
print(f"[DEBUG] ✗ 验证登录异常: {str(e)}")
return {
"success": False,
"message": f"验证失败: {str(e)}"
}
async def verify_login_with_storage(storage_file: str):
"""使用 storage_state 文件验证登录状态"""
try:
from pathlib import Path
from playwright.async_api import async_playwright
pth = Path(storage_file)
if not pth.exists():
return {
"success": False,
"message": "未找到登录状态文件"
}
# 使用 async_playwright 创建临时浏览器实例验证
async with async_playwright() as p:
# 使用与主浏览器相同的配置
browser = await p.chromium.launch(
headless=True, # 无头模式验证
args=["--no-sandbox", "--disable-setuid-sandbox"]
)
# 使用 storage_state 创建新 context
context = await browser.new_context(
storage_state=str(pth),
locale="zh-CN",
viewport={"width": 1200, "height": 800}
)
page = await context.new_page()
# 访问小红书主页
await page.goto("https://www.xiaohongshu.com", wait_until="domcontentloaded", timeout=60000)
await asyncio.sleep(1.2) # 等待页面加载
# 强拦截关键词 - 使用更可靠的元素检查方式
block_texts = ["扫码登录", "安全验证", "请先登录", "登录后查看"]
for text in block_texts:
try:
if await page.get_by_text(text).first.is_visible():
await browser.close()
return {
"success": False,
"message": f"登录状态无效或被拦截:页面出现「{text}」"
}
except Exception:
pass
# 弱判断:若明显出现"登录"且可见,可能未登录
try:
if await page.get_by_text("登录").first.is_visible():
await browser.close()
return {
"success": False,
"message": "疑似未登录(页面出现明显「登录」入口),建议重新登录保存状态"
}
except Exception:
pass
# 检查 URL 是否被重定向
current_url = page.url
if "login" in current_url.lower() or "404" in current_url:
await browser.close()
return {
"success": False,
"message": "被重定向到登录页面,登录状态无效"
}
# 检查页面标题
title = await page.title()
if "登录" in title or "404" in title:
await browser.close()
return {
"success": False,
"message": "页面标题显示登录或错误,登录状态无效"
}
# 所有检查都通过,认为登录有效
await browser.close()
# 创建 auth_state 文件作为备份
auth_file = os.path.join(config.DATA_DIR, "auth_state.json")
auth_data = {
"login_time": datetime.now().isoformat(),
"expire_time": (datetime.now() + timedelta(hours=24)).isoformat()
}
with open(auth_file, 'w', encoding='utf-8') as f:
json.dump(auth_data, f, ensure_ascii=False, indent=2)
print(f"[DEBUG] 登录验证成功")
return {
"success": True,
"message": "登录成功",
"logged_in": True,
"login_time": auth_data["login_time"],
"expire_time": auth_data["expire_time"],
"expire_in_hours": 24
}
except Exception as e:
print(f"[DEBUG] storage_state 验证失败: {str(e)}")
return {
"success": False,
"message": f"登录验证失败: {str(e)}"
}
@app.post("/api/logout")
async def logout():
"""退出登录"""