Compare commits
4 Commits
feature_20
...
542b20368e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
542b20368e | ||
| 71df2b605b | |||
| 5892dc3156 | |||
| 8787d5ddb7 |
111
app.py
111
app.py
@@ -2487,9 +2487,13 @@ def get_wechat_qrcode():
|
|||||||
# 生成唯一state参数
|
# 生成唯一state参数
|
||||||
state = uuid.uuid4().hex
|
state = uuid.uuid4().hex
|
||||||
|
|
||||||
|
print(f"🆕 [QRCODE] 生成新的微信二维码, state={state[:8]}...")
|
||||||
|
|
||||||
# URL编码回调地址
|
# URL编码回调地址
|
||||||
redirect_uri = urllib.parse.quote_plus(WECHAT_REDIRECT_URI)
|
redirect_uri = urllib.parse.quote_plus(WECHAT_REDIRECT_URI)
|
||||||
|
|
||||||
|
print(f"🔗 [QRCODE] 回调地址: {WECHAT_REDIRECT_URI}")
|
||||||
|
|
||||||
# 构建微信授权URL
|
# 构建微信授权URL
|
||||||
wechat_auth_url = (
|
wechat_auth_url = (
|
||||||
f"https://open.weixin.qq.com/connect/qrconnect?"
|
f"https://open.weixin.qq.com/connect/qrconnect?"
|
||||||
@@ -2507,6 +2511,8 @@ def get_wechat_qrcode():
|
|||||||
'wechat_unionid': None
|
'wechat_unionid': None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print(f"✅ [QRCODE] session 已存储, 当前总数: {len(wechat_qr_sessions)}")
|
||||||
|
|
||||||
return jsonify({"code":0,
|
return jsonify({"code":0,
|
||||||
"data":
|
"data":
|
||||||
{
|
{
|
||||||
@@ -2570,6 +2576,8 @@ def check_wechat_scan():
|
|||||||
del wechat_qr_sessions[session_id]
|
del wechat_qr_sessions[session_id]
|
||||||
return jsonify({'status': 'expired'}), 200
|
return jsonify({'status': 'expired'}), 200
|
||||||
|
|
||||||
|
print(f"📡 [CHECK] session_id: {session_id[:8]}..., status: {session['status']}, user_info: {session.get('user_info')}")
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': session['status'],
|
'status': session['status'],
|
||||||
'user_info': session.get('user_info'),
|
'user_info': session.get('user_info'),
|
||||||
@@ -2611,32 +2619,48 @@ def wechat_callback():
|
|||||||
state = request.args.get('state')
|
state = request.args.get('state')
|
||||||
error = request.args.get('error')
|
error = request.args.get('error')
|
||||||
|
|
||||||
|
print(f"🎯 [CALLBACK] 微信回调被调用!code={code[:10] if code else None}..., state={state[:8] if state else None}..., error={error}")
|
||||||
|
|
||||||
# 错误处理
|
# 错误处理
|
||||||
if error or not code or not state:
|
if error or not code or not state:
|
||||||
|
print(f"❌ [CALLBACK] 参数错误: error={error}, has_code={bool(code)}, has_state={bool(state)}")
|
||||||
return redirect('/auth/signin?error=wechat_auth_failed')
|
return redirect('/auth/signin?error=wechat_auth_failed')
|
||||||
|
|
||||||
# 验证state
|
# 验证state
|
||||||
if state not in wechat_qr_sessions:
|
if state not in wechat_qr_sessions:
|
||||||
|
print(f"❌ [CALLBACK] state 不在 wechat_qr_sessions 中: {state[:8]}...")
|
||||||
|
print(f" 当前 sessions: {list(wechat_qr_sessions.keys())}")
|
||||||
return redirect('/auth/signin?error=session_expired')
|
return redirect('/auth/signin?error=session_expired')
|
||||||
|
|
||||||
session_data = wechat_qr_sessions[state]
|
session_data = wechat_qr_sessions[state]
|
||||||
|
|
||||||
|
print(f"✅ [CALLBACK] 找到 session_data, mode={session_data.get('mode')}")
|
||||||
|
|
||||||
# 检查过期
|
# 检查过期
|
||||||
if time.time() > session_data['expires']:
|
if time.time() > session_data['expires']:
|
||||||
|
print(f"❌ [CALLBACK] session 已过期")
|
||||||
del wechat_qr_sessions[state]
|
del wechat_qr_sessions[state]
|
||||||
return redirect('/auth/signin?error=session_expired')
|
return redirect('/auth/signin?error=session_expired')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 获取access_token
|
# 获取access_token
|
||||||
|
print(f"🔑 [CALLBACK] 开始获取 access_token...")
|
||||||
token_data = get_wechat_access_token(code)
|
token_data = get_wechat_access_token(code)
|
||||||
if not token_data:
|
if not token_data:
|
||||||
|
print(f"❌ [CALLBACK] 获取 access_token 失败")
|
||||||
return redirect('/auth/signin?error=token_failed')
|
return redirect('/auth/signin?error=token_failed')
|
||||||
|
|
||||||
|
print(f"✅ [CALLBACK] 获取 access_token 成功, openid={token_data.get('openid', '')[:8]}...")
|
||||||
|
|
||||||
# 获取用户信息
|
# 获取用户信息
|
||||||
|
print(f"👤 [CALLBACK] 开始获取用户信息...")
|
||||||
user_info = get_wechat_userinfo(token_data['access_token'], token_data['openid'])
|
user_info = get_wechat_userinfo(token_data['access_token'], token_data['openid'])
|
||||||
if not user_info:
|
if not user_info:
|
||||||
|
print(f"❌ [CALLBACK] 获取用户信息失败")
|
||||||
return redirect('/auth/signin?error=userinfo_failed')
|
return redirect('/auth/signin?error=userinfo_failed')
|
||||||
|
|
||||||
|
print(f"✅ [CALLBACK] 获取用户信息成功, nickname={user_info.get('nickname', 'N/A')}")
|
||||||
|
|
||||||
# 查找或创建用户 / 或处理绑定
|
# 查找或创建用户 / 或处理绑定
|
||||||
openid = token_data['openid']
|
openid = token_data['openid']
|
||||||
unionid = user_info.get('unionid') or token_data.get('unionid')
|
unionid = user_info.get('unionid') or token_data.get('unionid')
|
||||||
@@ -2679,13 +2703,16 @@ def wechat_callback():
|
|||||||
return redirect('/home?bind=failed')
|
return redirect('/home?bind=failed')
|
||||||
|
|
||||||
user = None
|
user = None
|
||||||
|
is_new_user = False
|
||||||
|
|
||||||
if unionid:
|
if unionid:
|
||||||
user = User.query.filter_by(wechat_union_id=unionid).first()
|
user = User.query.filter_by(wechat_union_id=unionid).first()
|
||||||
if not user:
|
if not user:
|
||||||
user = User.query.filter_by(wechat_open_id=openid).first()
|
user = User.query.filter_by(wechat_open_id=openid).first()
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
# 创建新用户
|
# 创建新用户(自动注册)
|
||||||
|
is_new_user = True
|
||||||
# 先清理微信昵称
|
# 先清理微信昵称
|
||||||
raw_nickname = user_info.get('nickname', '微信用户')
|
raw_nickname = user_info.get('nickname', '微信用户')
|
||||||
# 创建临时用户实例以使用清理方法
|
# 创建临时用户实例以使用清理方法
|
||||||
@@ -2709,30 +2736,45 @@ def wechat_callback():
|
|||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# 更新最后登录时间
|
# 更新 wechat_qr_sessions 状态,供前端轮询检测
|
||||||
user.update_last_seen()
|
print(f"🔍 [DEBUG] state={state}, state in wechat_qr_sessions: {state in wechat_qr_sessions}")
|
||||||
|
|
||||||
# 设置session
|
|
||||||
session.permanent = True
|
|
||||||
session['user_id'] = user.id
|
|
||||||
session['username'] = user.username
|
|
||||||
session['logged_in'] = True
|
|
||||||
session['wechat_login'] = True # 标记是微信登录
|
|
||||||
|
|
||||||
# Flask-Login 登录
|
|
||||||
login_user(user, remember=True)
|
|
||||||
|
|
||||||
# 清理微信session(仅登录/注册流程清理;绑定流程在上方已处理,不在此处清理)
|
|
||||||
if state in wechat_qr_sessions:
|
if state in wechat_qr_sessions:
|
||||||
# 仅当不是绑定流程,或没有模式信息时清理
|
session_item = wechat_qr_sessions[state]
|
||||||
if not wechat_qr_sessions[state].get('mode'):
|
mode = session_item.get('mode')
|
||||||
del wechat_qr_sessions[state]
|
print(f"🔍 [DEBUG] session_item mode: {mode}, is_new_user: {is_new_user}")
|
||||||
|
# 不是绑定模式才更新为登录状态
|
||||||
|
if not mode:
|
||||||
|
new_status = 'register_success' if is_new_user else 'login_success'
|
||||||
|
session_item['status'] = new_status
|
||||||
|
session_item['user_info'] = {
|
||||||
|
'user_id': user.id,
|
||||||
|
'is_new_user': is_new_user
|
||||||
|
}
|
||||||
|
print(f"✅ [DEBUG] 更新 wechat_qr_sessions 状态: {new_status}, user_id: {user.id}")
|
||||||
|
else:
|
||||||
|
print(f"⚠️ [DEBUG] 跳过状态更新,因为 mode={mode}")
|
||||||
|
|
||||||
# 直接跳转到首页
|
# 返回一个简单的成功页面(前端轮询会检测到状态变化)
|
||||||
return redirect('/home')
|
return '''
|
||||||
|
<html>
|
||||||
|
<head><title>授权成功</title></head>
|
||||||
|
<body>
|
||||||
|
<h2>微信授权成功</h2>
|
||||||
|
<p>请返回原页面继续操作...</p>
|
||||||
|
<script>
|
||||||
|
// 尝试关闭窗口(如果是弹窗的话)
|
||||||
|
setTimeout(function() {
|
||||||
|
window.close();
|
||||||
|
}, 1000);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
''', 200
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ 微信登录失败: {e}")
|
print(f"❌ [CALLBACK] 微信登录失败: {e}")
|
||||||
|
import traceback
|
||||||
|
print(f"❌ [CALLBACK] 错误堆栈:\n{traceback.format_exc()}")
|
||||||
db.session.rollback()
|
db.session.rollback()
|
||||||
return redirect('/auth/signin?error=login_failed')
|
return redirect('/auth/signin?error=login_failed')
|
||||||
|
|
||||||
@@ -2747,16 +2789,16 @@ def login_with_wechat():
|
|||||||
return jsonify({'success': False, 'error': 'session_id不能为空'}), 400
|
return jsonify({'success': False, 'error': 'session_id不能为空'}), 400
|
||||||
|
|
||||||
# 验证session
|
# 验证session
|
||||||
session = wechat_qr_sessions.get(session_id)
|
wechat_session = wechat_qr_sessions.get(session_id)
|
||||||
if not session:
|
if not wechat_session:
|
||||||
return jsonify({'success': False, 'error': '会话不存在或已过期'}), 400
|
return jsonify({'success': False, 'error': '会话不存在或已过期'}), 400
|
||||||
|
|
||||||
# 检查session状态
|
# 检查session状态
|
||||||
if session['status'] not in ['login_ready', 'register_ready']:
|
if wechat_session['status'] not in ['login_success', 'register_success']:
|
||||||
return jsonify({'success': False, 'error': '会话状态无效'}), 400
|
return jsonify({'success': False, 'error': '会话状态无效'}), 400
|
||||||
|
|
||||||
# 检查是否有用户信息
|
# 检查是否有用户信息
|
||||||
user_info = session.get('user_info')
|
user_info = wechat_session.get('user_info')
|
||||||
if not user_info or not user_info.get('user_id'):
|
if not user_info or not user_info.get('user_id'):
|
||||||
return jsonify({'success': False, 'error': '用户信息不完整'}), 400
|
return jsonify({'success': False, 'error': '用户信息不完整'}), 400
|
||||||
|
|
||||||
@@ -2768,18 +2810,33 @@ def login_with_wechat():
|
|||||||
# 更新最后登录时间
|
# 更新最后登录时间
|
||||||
user.update_last_seen()
|
user.update_last_seen()
|
||||||
|
|
||||||
# 清除session
|
# 设置 Flask session
|
||||||
|
session.permanent = True
|
||||||
|
session['user_id'] = user.id
|
||||||
|
session['username'] = user.username
|
||||||
|
session['logged_in'] = True
|
||||||
|
session['wechat_login'] = True # 标记是微信登录
|
||||||
|
|
||||||
|
# Flask-Login 登录
|
||||||
|
login_user(user, remember=True)
|
||||||
|
|
||||||
|
# 判断是否为新用户
|
||||||
|
is_new_user = user_info.get('is_new_user', False)
|
||||||
|
|
||||||
|
# 清除 wechat_qr_sessions
|
||||||
del wechat_qr_sessions[session_id]
|
del wechat_qr_sessions[session_id]
|
||||||
|
|
||||||
# 生成登录响应
|
# 生成登录响应
|
||||||
response_data = {
|
response_data = {
|
||||||
'success': True,
|
'success': True,
|
||||||
'message': '登录成功' if session['status'] == 'login_ready' else '注册并登录成功',
|
'message': '注册成功' if is_new_user else '登录成功',
|
||||||
|
'isNewUser': is_new_user,
|
||||||
'user': {
|
'user': {
|
||||||
'id': user.id,
|
'id': user.id,
|
||||||
'username': user.username,
|
'username': user.username,
|
||||||
'nickname': user.nickname or user.username,
|
'nickname': user.nickname or user.username,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
|
'phone': user.phone,
|
||||||
'avatar_url': user.avatar_url,
|
'avatar_url': user.avatar_url,
|
||||||
'has_wechat': True,
|
'has_wechat': True,
|
||||||
'wechat_open_id': user.wechat_open_id,
|
'wechat_open_id': user.wechat_open_id,
|
||||||
|
|||||||
@@ -119,8 +119,12 @@ export default function WechatRegister() {
|
|||||||
*/
|
*/
|
||||||
const handleLoginSuccess = useCallback(async (sessionId, status) => {
|
const handleLoginSuccess = useCallback(async (sessionId, status) => {
|
||||||
try {
|
try {
|
||||||
|
logger.info('WechatRegister', '开始调用登录接口', { sessionId: sessionId.substring(0, 8) + '...', status });
|
||||||
|
|
||||||
const response = await authService.loginWithWechat(sessionId);
|
const response = await authService.loginWithWechat(sessionId);
|
||||||
|
|
||||||
|
logger.info('WechatRegister', '登录接口返回', { success: response?.success, hasUser: !!response?.user });
|
||||||
|
|
||||||
if (response?.success) {
|
if (response?.success) {
|
||||||
// Session cookie 会自动管理,不需要手动存储
|
// Session cookie 会自动管理,不需要手动存储
|
||||||
// 如果后端返回了 token,可以选择性存储(兼容旧方式)
|
// 如果后端返回了 token,可以选择性存储(兼容旧方式)
|
||||||
@@ -178,6 +182,12 @@ export default function WechatRegister() {
|
|||||||
const { status } = response;
|
const { status } = response;
|
||||||
logger.debug('WechatRegister', '微信状态', { status });
|
logger.debug('WechatRegister', '微信状态', { status });
|
||||||
|
|
||||||
|
logger.debug('WechatRegister', '检测到微信状态', {
|
||||||
|
sessionId: wechatSessionId.substring(0, 8) + '...',
|
||||||
|
status,
|
||||||
|
userInfo: response.user_info
|
||||||
|
});
|
||||||
|
|
||||||
// 组件卸载后不再更新状态
|
// 组件卸载后不再更新状态
|
||||||
if (!isMountedRef.current) return;
|
if (!isMountedRef.current) return;
|
||||||
|
|
||||||
@@ -185,6 +195,7 @@ export default function WechatRegister() {
|
|||||||
|
|
||||||
// 处理成功状态
|
// 处理成功状态
|
||||||
if (status === WECHAT_STATUS.LOGIN_SUCCESS || status === WECHAT_STATUS.REGISTER_SUCCESS) {
|
if (status === WECHAT_STATUS.LOGIN_SUCCESS || status === WECHAT_STATUS.REGISTER_SUCCESS) {
|
||||||
|
logger.info('WechatRegister', '检测到登录成功状态,停止轮询', { status });
|
||||||
clearTimers(); // 停止轮询
|
clearTimers(); // 停止轮询
|
||||||
sessionIdRef.current = null; // 清理 sessionId
|
sessionIdRef.current = null; // 清理 sessionId
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user