224 lines
7.7 KiB
Python
224 lines
7.7 KiB
Python
"""
|
||
前端一键扫码登录辅助页面
|
||
客户在自己的浏览器中扫码,JavaScript自动提取Cookie并上传到服务器
|
||
"""
|
||
from fastapi import APIRouter, Request
|
||
from fastapi.responses import HTMLResponse
|
||
from app.core.config import settings
|
||
|
||
router = APIRouter()
|
||
|
||
@router.get("/login-helper/{platform}", response_class=HTMLResponse)
|
||
async def login_helper_page(platform: str, request: Request):
|
||
"""
|
||
提供一个HTML页面,让用户在自己的浏览器中登录平台
|
||
登录后JavaScript自动提取Cookie并POST回服务器
|
||
"""
|
||
|
||
platform_urls = {
|
||
"bilibili": "https://www.bilibili.com/",
|
||
"douyin": "https://creator.douyin.com/",
|
||
"xiaohongshu": "https://creator.xiaohongshu.com/",
|
||
"weixin": "https://channels.weixin.qq.com/"
|
||
}
|
||
|
||
platform_names = {
|
||
"bilibili": "B站",
|
||
"douyin": "抖音",
|
||
"xiaohongshu": "小红书",
|
||
"weixin": "微信视频号"
|
||
}
|
||
|
||
if platform not in platform_urls:
|
||
return "<h1>不支持的平台</h1>"
|
||
|
||
# 获取服务器地址(用于回传Cookie)
|
||
server_url = str(request.base_url).rstrip('/')
|
||
|
||
html_content = f"""
|
||
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>{platform_names[platform]} 一键登录</title>
|
||
<style>
|
||
body {{
|
||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
margin: 0;
|
||
padding: 20px;
|
||
min-height: 100vh;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}}
|
||
.container {{
|
||
background: white;
|
||
border-radius: 20px;
|
||
padding: 50px;
|
||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||
max-width: 700px;
|
||
width: 100%;
|
||
}}
|
||
h1 {{
|
||
color: #333;
|
||
margin: 0 0 30px 0;
|
||
text-align: center;
|
||
font-size: 32px;
|
||
}}
|
||
.step {{
|
||
display: flex;
|
||
align-items: flex-start;
|
||
margin: 25px 0;
|
||
padding: 20px;
|
||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||
border-radius: 12px;
|
||
border-left: 5px solid #667eea;
|
||
}}
|
||
.step-number {{
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-weight: bold;
|
||
font-size: 20px;
|
||
margin-right: 20px;
|
||
flex-shrink: 0;
|
||
}}
|
||
.step-content {{
|
||
flex: 1;
|
||
}}
|
||
.step-title {{
|
||
font-weight: 600;
|
||
font-size: 18px;
|
||
margin-bottom: 8px;
|
||
color: #333;
|
||
}}
|
||
.step-desc {{
|
||
color: #666;
|
||
line-height: 1.6;
|
||
}}
|
||
.bookmarklet {{
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 15px 30px;
|
||
border-radius: 10px;
|
||
text-decoration: none;
|
||
display: inline-block;
|
||
font-weight: 600;
|
||
font-size: 18px;
|
||
margin: 20px 0;
|
||
cursor: move;
|
||
border: 3px dashed white;
|
||
transition: transform 0.2s;
|
||
}}
|
||
.bookmarklet:hover {{
|
||
transform: scale(1.05);
|
||
}}
|
||
.bookmarklet-container {{
|
||
text-align: center;
|
||
margin: 30px 0;
|
||
padding: 30px;
|
||
background: #f8f9fa;
|
||
border-radius: 12px;
|
||
}}
|
||
.instruction {{
|
||
font-size: 14px;
|
||
color: #666;
|
||
margin-top: 10px;
|
||
}}
|
||
.highlight {{
|
||
background: #fff3cd;
|
||
padding: 2px 6px;
|
||
border-radius: 4px;
|
||
font-weight: 600;
|
||
}}
|
||
.btn {{
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
border: none;
|
||
padding: 15px 40px;
|
||
border-radius: 10px;
|
||
font-size: 18px;
|
||
cursor: pointer;
|
||
font-weight: 600;
|
||
width: 100%;
|
||
margin-top: 20px;
|
||
transition: transform 0.2s;
|
||
}}
|
||
.btn:hover {{
|
||
transform: translateY(-2px);
|
||
}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>🔐 {platform_names[platform]} 一键登录</h1>
|
||
|
||
<div class="step">
|
||
<div class="step-number">1</div>
|
||
<div class="step-content">
|
||
<div class="step-title">拖拽书签到书签栏</div>
|
||
<div class="step-desc">
|
||
将下方的"<span class="highlight">保存{platform_names[platform]}登录</span>"按钮拖拽到浏览器书签栏
|
||
<br><small>(如果书签栏未显示,按 Ctrl+Shift+B 显示)</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bookmarklet-container">
|
||
<a href="javascript:(function(){{var c=document.cookie;if(!c){{alert('请先登录{platform_names[platform]}');return;}}fetch('{server_url}/api/publish/cookies/save/{platform}',{{method:'POST',headers:{{'Content-Type':'application/json'}},body:JSON.stringify({{cookie_string:c}})}}).then(r=>r.json()).then(d=>{{if(d.success){{alert('✅ 登录成功!');window.opener&&window.opener.location.reload();}}else{{alert('❌ '+d.message);}}}}
|
||
|
||
).catch(e=>alert('提交失败:'+e));}})();"
|
||
class="bookmarklet"
|
||
onclick="alert('请拖拽此按钮到书签栏,不要点击!'); return false;">
|
||
🔖 保存{platform_names[platform]}登录
|
||
</a>
|
||
<div class="instruction">
|
||
⬆️ <strong>拖拽此按钮到浏览器顶部书签栏</strong>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step">
|
||
<div class="step-number">2</div>
|
||
<div class="step-content">
|
||
<div class="step-title">登录 {platform_names[platform]}</div>
|
||
<div class="step-desc">
|
||
点击下方按钮打开{platform_names[platform]}登录页,扫码登录
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<button class="btn" onclick="window.open('{platform_urls[platform]}', 'login_tab')">
|
||
🚀 打开{platform_names[platform]}登录页
|
||
</button>
|
||
|
||
<div class="step">
|
||
<div class="step-number">3</div>
|
||
<div class="step-content">
|
||
<div class="step-title">一键保存登录</div>
|
||
<div class="step-desc">
|
||
登录成功后,点击书签栏的"<span class="highlight">保存{platform_names[platform]}登录</span>"书签
|
||
<br>系统会自动提取并保存Cookie,完成!
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<hr style="margin: 40px 0; border: none; border-top: 2px solid #eee;">
|
||
|
||
<div style="text-align: center; color: #999; font-size: 14px;">
|
||
<p>💡 <strong>提示</strong>:书签只需拖拽一次,下次登录直接点击书签即可</p>
|
||
<p>🔒 所有数据仅在您的浏览器和服务器之间传输,安全可靠</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
"""
|
||
|
||
return HTMLResponse(content=html_content)
|