fix feishu reauth for online docs

This commit is contained in:
wuyang6
2026-07-02 14:02:01 +08:00
parent 0007d99763
commit 8eadc25b19
5 changed files with 243 additions and 13 deletions
+54 -11
View File
@@ -1132,6 +1132,7 @@ class SessionUpdate(BaseModel):
class FeishuAccountRequest(BaseModel):
account_id: str | None = None
force: bool = False
class FeishuOnlineDocRequest(BaseModel):
@@ -1616,7 +1617,7 @@ def create_app(state: AgentState) -> FastAPI:
@app.post('/api/integrations/feishu/login')
async def feishu_login(payload: FeishuAccountRequest) -> dict[str, Any]:
return _start_feishu_login(state, payload.account_id)
return _start_feishu_login(state, payload.account_id, force=payload.force)
@app.post('/api/integrations/feishu/logout')
async def feishu_logout(payload: FeishuAccountRequest) -> dict[str, Any]:
@@ -1684,6 +1685,20 @@ def create_app(state: AgentState) -> FastAPI:
except OSError as exc:
raise HTTPException(status_code=400, detail=f'读取文件失败: {exc}')
except Exception as exc:
if _is_feishu_auth_error(str(exc)):
_stop_feishu_login(payload.account_id)
logout_result = _run_feishu_cli(paths, ['logout'], timeout_seconds=30)
status = _feishu_status_payload(state, payload.account_id)
status['logout_output'] = logout_result.get('output')
raise HTTPException(
status_code=409,
detail={
'code': 'feishu_auth_expired',
'message': '飞书登录已过期或未登录,请重新授权后再转换。',
'force_login': True,
'status': status,
},
)
target_name = '飞书表格' if kind == 'sheet' else '飞书文档'
raise HTTPException(status_code=502, detail=f'{target_name}创建失败: {exc}')
url = _extract_first_url(rendered)
@@ -4379,16 +4394,36 @@ def _run_feishu_cli(
}
def _is_feishu_auth_error(text: str) -> bool:
lowered = text.lower()
markers = (
'not logged in',
'no credentials',
'unauthorized',
'unauthenticated',
'login expired',
'token expired',
'invalid token',
'access token expired',
'refresh token expired',
'登录已过期',
'授权已过期',
'未登录',
'未授权',
'凭证已过期',
'认证失败',
'请重新登录',
'重新授权',
)
return any(marker in lowered for marker in markers)
def _feishu_status_payload(state: AgentState, account_id: str | None) -> dict[str, Any]:
paths = _feishu_paths(state, account_id)
_reap_feishu_login(account_id)
result = _run_feishu_cli(paths, ['status'], timeout_seconds=30)
output = str(result.get('output') or '')
lowered = output.lower()
logged_in = result.get('returncode') == 0 and not any(
marker in lowered
for marker in ('not logged in', '未登录', 'no credentials')
)
logged_in = result.get('returncode') == 0 and not _is_feishu_auth_error(output)
pending = _feishu_login_snapshot(account_id)
payload: dict[str, Any] = {
'logged_in': logged_in,
@@ -4405,15 +4440,21 @@ def _feishu_status_payload(state: AgentState, account_id: str | None) -> dict[st
return payload
def _start_feishu_login(state: AgentState, account_id: str | None) -> dict[str, Any]:
status = _feishu_status_payload(state, account_id)
if status.get('logged_in'):
return status
def _start_feishu_login(
state: AgentState,
account_id: str | None,
*,
force: bool = False,
) -> dict[str, Any]:
if not force:
status = _feishu_status_payload(state, account_id)
if status.get('logged_in'):
return status
key = _feishu_login_key(account_id)
with _FEISHU_LOGIN_LOCK:
existing = _FEISHU_LOGIN_PROCESSES.get(key)
if existing is not None and existing.process.poll() is None:
if not force and existing is not None and existing.process.poll() is None:
return {
'logged_in': False,
'status': 'login_pending',
@@ -4422,6 +4463,8 @@ def _start_feishu_login(state: AgentState, account_id: str | None) -> dict[str,
_FEISHU_LOGIN_PROCESSES.pop(key, None)
paths = _feishu_paths(state, account_id)
if force:
_run_feishu_cli(paths, ['logout'], timeout_seconds=30)
env = os.environ.copy()
env.update(_feishu_env(paths))
try: