D109续③ · 登录改为代码仓库账号密码(告别长Token)
This commit is contained in:
parent
f5033df659
commit
ff38c723ca
@ -33,7 +33,7 @@ from engine import (
|
|||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
APP_NAME = "语料采集系统 Corpus Agent"
|
APP_NAME = "语料采集系统 Corpus Agent"
|
||||||
VERSION = "1.0.1"
|
VERSION = "1.1.0"
|
||||||
|
|
||||||
# 存储路径
|
# 存储路径
|
||||||
DATA_DIR = Path(os.environ.get("CORPUS_DATA_DIR", "./data"))
|
DATA_DIR = Path(os.environ.get("CORPUS_DATA_DIR", "./data"))
|
||||||
@ -85,6 +85,10 @@ class CorpusSave(BaseModel):
|
|||||||
class LoginRequest(BaseModel):
|
class LoginRequest(BaseModel):
|
||||||
gitea_token: str
|
gitea_token: str
|
||||||
|
|
||||||
|
class PasswordLoginRequest(BaseModel):
|
||||||
|
username: str
|
||||||
|
password: str
|
||||||
|
|
||||||
class ChatRequest(BaseModel):
|
class ChatRequest(BaseModel):
|
||||||
message: str
|
message: str
|
||||||
persona: str = "zhuyuan" # zhuyuan | shuangyan
|
persona: str = "zhuyuan" # zhuyuan | shuangyan
|
||||||
@ -294,6 +298,50 @@ async def login(req: LoginRequest):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@app.post("/api/auth/login/password")
|
||||||
|
async def login_with_password(req: PasswordLoginRequest):
|
||||||
|
"""使用代码仓库账号密码登录(复用首页的 /api/verify 接口)"""
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
if not req.username.strip() or not req.password:
|
||||||
|
raise HTTPException(400, "账号和密码不能为空")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 调用本地验证接口(nginx: /api/verify → 127.0.0.1:3905/verify)
|
||||||
|
verify_data = json.dumps({"user": req.username, "password": req.password}).encode()
|
||||||
|
verify_req = urllib.request.Request(
|
||||||
|
"http://127.0.0.1:3905/verify",
|
||||||
|
data=verify_data,
|
||||||
|
headers={"Content-Type": "application/json"}
|
||||||
|
)
|
||||||
|
with urllib.request.urlopen(verify_req, timeout=10) as resp:
|
||||||
|
result = json.loads(resp.read().decode())
|
||||||
|
|
||||||
|
if not result.get("ok"):
|
||||||
|
raise HTTPException(401, "账号或密码错误")
|
||||||
|
|
||||||
|
username = result.get("username", req.username)
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(500, f"验证服务不可达: {str(e)}")
|
||||||
|
|
||||||
|
token = create_session(username)
|
||||||
|
|
||||||
|
# 统计现有语料
|
||||||
|
corpus = load_corpus(username)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ok": True,
|
||||||
|
"token": token,
|
||||||
|
"username": username,
|
||||||
|
"stats": {
|
||||||
|
"total_samples": len(corpus),
|
||||||
|
"total_chars": sum(len(json.dumps(s, ensure_ascii=False)) for s in corpus),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@app.get("/api/auth/check")
|
@app.get("/api/auth/check")
|
||||||
async def check_session(token: str = Query(...)):
|
async def check_session(token: str = Query(...)):
|
||||||
username = get_user_from_token(token)
|
username = get_user_from_token(token)
|
||||||
|
|||||||
@ -121,21 +121,24 @@
|
|||||||
<div class="header">
|
<div class="header">
|
||||||
<h1>🧠 语料采集系统 · Corpus Agent</h1>
|
<h1>🧠 语料采集系统 · Corpus Agent</h1>
|
||||||
<p>自动采集 · 脱敏 · 格式化 · 对话式语料分析</p>
|
<p>自动采集 · 脱敏 · 格式化 · 对话式语料分析</p>
|
||||||
<div class="version">v1.0.1 · 国作登字-2026-A-00037559</div>
|
<div class="version">v1.1.0 · 国作登字-2026-A-00037559</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Login -->
|
<!-- Login -->
|
||||||
<div class="card" id="login-section">
|
<div class="card" id="login-section">
|
||||||
<div class="login-box">
|
<div class="login-box">
|
||||||
<h2 style="margin-bottom:8px">登录</h2>
|
<h2 style="margin-bottom:8px">登录</h2>
|
||||||
<p style="color:#666; font-size:13px; margin-bottom:20px">
|
<p style="color:#666; font-size:13px; margin-bottom:8px">
|
||||||
使用 Gitea Access Token 登录
|
使用代码仓库账号登录
|
||||||
</p>
|
</p>
|
||||||
<input type="password" id="token-input" placeholder="输入 Gitea Access Token">
|
<input type="text" id="login-user" placeholder="Gitea 账号" style="width:260px" onkeydown="if(event.key==='Enter')login()">
|
||||||
|
<br>
|
||||||
|
<input type="password" id="login-pass" placeholder="密码" style="width:260px" onkeydown="if(event.key==='Enter')login()">
|
||||||
<br>
|
<br>
|
||||||
<button class="btn btn-primary" onclick="login()">登录</button>
|
<button class="btn btn-primary" onclick="login()">登录</button>
|
||||||
|
<div id="login-error" style="color:#ef4444;font-size:13px;margin-top:8px;display:none"></div>
|
||||||
<p style="color:#999; font-size:12px; margin-top:12px">
|
<p style="color:#999; font-size:12px; margin-top:12px">
|
||||||
访问 <a href="https://guanghulab.com/user/settings/applications" target="_blank" style="color:#4a6cf7">Gitea → 设置 → 应用</a> 创建 Token
|
与 <a href="https://guanghulab.com/" target="_blank" style="color:#4a6cf7">光湖联邦首页</a> 使用同一套账号
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -288,7 +291,7 @@
|
|||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
语料采集系统 v1.0.1 · 铸渊 · ICE-GL-ZY001 · 国作登字-2026-A-00037559
|
语料采集系统 v1.1.0 · 铸渊 · ICE-GL-ZY001 · 国作登字-2026-A-00037559
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -311,18 +314,22 @@ async function api(method, path, body) {
|
|||||||
|
|
||||||
// ─── Login ─────────────────────────────────────────────────
|
// ─── Login ─────────────────────────────────────────────────
|
||||||
async function login() {
|
async function login() {
|
||||||
const t = document.getElementById('token-input').value.trim();
|
const user = document.getElementById('login-user').value.trim();
|
||||||
if (!t) return alert('请输入Token');
|
const pass = document.getElementById('login-pass').value;
|
||||||
const r = await fetch(`${API}/api/auth/login`, {
|
const errEl = document.getElementById('login-error');
|
||||||
|
if (!user || !pass) { errEl.textContent = '请输入账号和密码'; errEl.style.display = 'block'; return; }
|
||||||
|
errEl.style.display = 'none';
|
||||||
|
const r = await fetch(`${API}/api/auth/login/password`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({gitea_token: t})
|
body: JSON.stringify({username: user, password: pass})
|
||||||
});
|
});
|
||||||
const d = await r.json();
|
const d = await r.json();
|
||||||
if (!d.ok) return alert('登录失败: ' + JSON.stringify(d));
|
if (!d.ok) { errEl.textContent = d.detail || '登录失败'; errEl.style.display = 'block'; return; }
|
||||||
token = d.token;
|
token = d.token;
|
||||||
username = d.username;
|
username = d.username;
|
||||||
localStorage.setItem('corpus_token', token);
|
localStorage.setItem('corpus_token', token);
|
||||||
|
document.getElementById('login-pass').value = '';
|
||||||
document.getElementById('login-section').classList.add('hidden');
|
document.getElementById('login-section').classList.add('hidden');
|
||||||
document.getElementById('main-section').classList.remove('hidden');
|
document.getElementById('main-section').classList.remove('hidden');
|
||||||
document.getElementById('display-name').textContent = username;
|
document.getElementById('display-name').textContent = username;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user