ts
This commit is contained in:
+195
-52
@@ -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():
|
||||
"""退出登录"""
|
||||
|
||||
Reference in New Issue
Block a user