import hashlib import requests from flask import session, redirect, url_for, request from functools import wraps LOGIN_URL = "https://api.infi.cn/board/user/nc/accountLogin" USER_API = "https://api.infi.cn/bsg/user/getMyInfo" def infi_login(account, password): """使用英飞API登录""" try: login_data = { "account": account, "passwd": hashlib.md5(password.encode()).hexdigest(), "loginOriginType": 1 } login_response = requests.post( LOGIN_URL, json=login_data, headers={"Content-Type": "application/json"}, timeout=10 ) print(f"[debug] infi_login: LOGIN_URL status={login_response.status_code}") print(f"[debug] infi_login: LOGIN_URL body={login_response.text[:1000]}") if login_response.status_code != 200: return None, f"API请求失败,HTTP {login_response.status_code}" try: data = login_response.json() except ValueError: print("[debug] infi_login: 无法解析登录响应为 JSON", login_response.text[:1000]) return None, "无法解析登录响应为 JSON" # 兼容不同的返回格式:优先从 obj.token 拿 token,其次尝试顶层 token 或 obj 为字符串的情况 token = None if isinstance(data, dict): obj = data.get('obj') if isinstance(obj, dict) and obj.get('token'): token = obj.get('token') elif isinstance(obj, str) and obj: token = obj elif data.get('token'): token = data.get('token') if not token: # 如果存在 code/msg,把它们返回以便排查 code = data.get('code') if isinstance(data, dict) else None msg = data.get('msg') if isinstance(data, dict) else None detail = f" code={code}" if code is not None else "" print(f"[debug] infi_login: 未找到 token,响应 data={data}") if msg: return None, f"登录失败: {msg}{detail}" return None, f"登录失败:未在响应中找到 token。响应: {data}" # 获取用户信息 user_response = requests.post( USER_API, headers={ "access-token": token, "Origin": "https://infi.cn", "Content-Type": "application/json" }, timeout=10 ) print(f"[debug] infi_login: USER_API status={user_response.status_code}") print(f"[debug] infi_login: USER_API body={user_response.text[:1000]}") if user_response.status_code != 200: body = user_response.text[:1000] return None, f"获取用户信息失败,HTTP {user_response.status_code} 响应: {body}" try: user_data = user_response.json() except ValueError: print("[debug] infi_login: 无法解析用户信息响应为 JSON", user_response.text[:1000]) return None, "无法解析用户信息响应为 JSON" # 兼容不同返回格式:服务端有时使用 code==0 表示成功 if isinstance(user_data, dict) and user_data.get('code') is not None and user_data.get('code') not in (0, 200): print(f"[debug] infi_login: user_data indicates failure: {user_data}") return None, f"获取用户信息失败: {user_data.get('msg', '')} 响应: {user_data}" user_obj = None if isinstance(user_data, dict): user_obj = user_data.get('obj') or user_data return { 'token': token, 'user_info': user_obj }, None except Exception as e: # 针对网络/DNS 解析类错误返回更有帮助的提示 msg = str(e) if 'NameResolutionError' in msg or 'Failed to resolve' in msg or 'Max retries exceeded' in msg: return None, ( "网络错误:无法解析 api.infi.cn(DNS)。请检查网络连接、DNS 或代理设置。" " 可尝试命令:\n 1) `nslookup api.infi.cn`\n 2) `ping api.infi.cn`\n" " 或切换网络/使用 VPN、设置正确的 `HTTP(S)_PROXY` 环境变量。" ) return None, f"登录异常: {msg}" def login_required(f): """登录装饰器""" @wraps(f) def decorated_function(*args, **kwargs): if 'user_account' not in session: return redirect(url_for('login')) return f(*args, **kwargs) return decorated_function