114 lines
4.5 KiB
Python
114 lines
4.5 KiB
Python
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 |