@@ -253,6 +253,94 @@ def interactive_login():
253253 return csrf_token , corp_id , user_id , base_url , cookies
254254
255255
256+ # ── 终端 ASCII 二维码登录 ─────────────────────────────
257+
258+
259+ def qrcode_login ():
260+ """在终端显示 ASCII 二维码,供用户扫码登录。"""
261+ print ("\n 📱 正在获取登录二维码..." , file = sys .stderr )
262+
263+ import qrcode
264+ import time
265+
266+ with sync_playwright () as pw :
267+ browser = pw .chromium .launch (headless = True )
268+ context = browser .new_context ()
269+ page = context .new_page ()
270+
271+ qr_url = None
272+
273+ def handle_response (response ):
274+ nonlocal qr_url
275+ url = response .url
276+ if "generate_qrcode" in url or "/generate_qrcode?" in url :
277+ print (f" Found QR API: { url [:60 ]} " , file = sys .stderr )
278+ try :
279+ data = response .json ()
280+ print (f" Response: { data } " , file = sys .stderr )
281+ if data .get ("success" ) and data .get ("result" ):
282+ qr_url = data ["result" ]
283+ except Exception as e :
284+ print (f" Error: { e } " , file = sys .stderr )
285+
286+ page .on ("response" , handle_response )
287+
288+ dingtalk_login_url = "https://login.dingtalk.com/oauth2/challenge.htm?redirect_uri=https%3A%2F%2Fwww.aliwork.com%2Fdingtalk_sso_call_back%3Fcontinue%3Dhttps%253A%252F%252Fwww.aliwork.com%252FworkPlatform&response_type=code&client_id=suite9xvlxxerybljwheo&scope=openid+corpid&lang=zh_CN"
289+ page .goto (dingtalk_login_url , timeout = 120_000 )
290+
291+ for _ in range (20 ):
292+ if qr_url :
293+ break
294+ time .sleep (0.5 )
295+
296+ if not qr_url :
297+ print (" ❌ 无法获取二维码" , file = sys .stderr )
298+ browser .close ()
299+ sys .exit (1 )
300+
301+ print (f" ✅ 二维码获取成功\n " , file = sys .stderr )
302+
303+ qr = qrcode .QRCode (version = 1 , box_size = 1 , border = 1 )
304+ qr .add_data (qr_url )
305+ qr .make (fit = True )
306+
307+ print ("─" * 40 , file = sys .stderr )
308+ print (" 请使用钉钉扫码登录" , file = sys .stderr )
309+ print ("─" * 40 + "\n " , file = sys .stderr )
310+
311+ qr .print_ascii (tty = True )
312+
313+ print ("\n " + "─" * 40 , file = sys .stderr )
314+ print (" 等待扫码登录(最长 10 分钟)..." , file = sys .stderr )
315+
316+ start_time = time .time ()
317+ while time .time () - start_time < 600 :
318+ if "workPlatform" in page .url :
319+ break
320+ time .sleep (2 )
321+
322+ if "workPlatform" not in page .url :
323+ print (" ⏰ 登录超时" , file = sys .stderr )
324+ browser .close ()
325+ sys .exit (1 )
326+
327+ page .wait_for_load_state ("networkidle" )
328+ print (" ✅ 登录成功!" , file = sys .stderr )
329+
330+ post_login_parsed = urlparse (page .url )
331+ base_url = f"{ post_login_parsed .scheme } ://{ post_login_parsed .netloc } "
332+ cookies = context .cookies ()
333+ browser .close ()
334+
335+ csrf_token , corp_id , user_id = extract_info_from_cookies (cookies )
336+ if not csrf_token :
337+ print (" ❌ 登录成功但无 csrf_token" , file = sys .stderr )
338+ sys .exit (1 )
339+
340+ save_login_cache (cookies , base_url )
341+ return csrf_token , corp_id , user_id , base_url , cookies
342+
343+
256344# ── 核心入口 ──────────────────────────────────────────
257345
258346
@@ -324,6 +412,13 @@ def main():
324412 print ("=" * 50 , file = sys .stderr )
325413
326414 csrf_token , corp_id , user_id , base_url , cookies = refresh_csrf_token ()
415+ elif "--qrcode" in sys .argv :
416+ print ("=" * 50 , file = sys .stderr )
417+ print (" yida-login - 终端二维码登录" , file = sys .stderr )
418+ print ("=" * 50 , file = sys .stderr )
419+ print (f"\n 登录地址: { LOGIN_URL } " , file = sys .stderr )
420+
421+ csrf_token , corp_id , user_id , base_url , cookies = qrcode_login ()
327422 else :
328423 print ("=" * 50 , file = sys .stderr )
329424 print (" yida-login - 宜搭登录态管理工具" , file = sys .stderr )
0 commit comments