2026-1-6
This commit is contained in:
298
ver_2512121646/auth_routes.py
Normal file
298
ver_2512121646/auth_routes.py
Normal file
@@ -0,0 +1,298 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
认证接口
|
||||
"""
|
||||
|
||||
from flask import Blueprint, request, jsonify
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from auth_utils import AuthUtils
|
||||
from database_config import get_db_manager, format_datetime_fields
|
||||
from log_utils import log_create, log_update, log_delete, log_error, log_operation
|
||||
|
||||
logger = logging.getLogger('article_server')
|
||||
|
||||
# 创建蓝图
|
||||
auth_bp = Blueprint('auth', __name__, url_prefix='/api/auth')
|
||||
|
||||
@auth_bp.route('/login', methods=['POST'])
|
||||
def login():
|
||||
"""统一登录接口(支持企业主和员工)"""
|
||||
client_ip = request.environ.get('HTTP_X_FORWARDED_FOR', request.environ.get('REMOTE_ADDR', '未知'))
|
||||
logger.info(f"[用户登录] 开始处理登录请求, IP: {client_ip}")
|
||||
|
||||
try:
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
logger.warning(f"[用户登录] 请求参数为空, IP: {client_ip}")
|
||||
return jsonify({
|
||||
'code': 400,
|
||||
'message': '请求参数错误',
|
||||
'data': None
|
||||
}), 400
|
||||
|
||||
# 支持手机号或用户名登录
|
||||
phone = data.get('phone')
|
||||
username = data.get('username')
|
||||
password = data.get('password')
|
||||
|
||||
login_account = phone or username
|
||||
logger.info(f"[用户登录] 收到登录请求, 账号: {login_account}, IP: {client_ip}")
|
||||
|
||||
if not login_account or not password:
|
||||
logger.warning(f"[用户登录] 账号或密码为空, 账号: {login_account}, IP: {client_ip}")
|
||||
return jsonify({
|
||||
'code': 400,
|
||||
'message': '账号和密码不能为空',
|
||||
'data': None
|
||||
}), 400
|
||||
|
||||
# 第一步:先在 ai_users 表查询用户
|
||||
# 从ai_authors表获取xhs_account字段以优化性能
|
||||
logger.info(f"[用户登录] 开始在ai_users表查询用户, 账号: {login_account}")
|
||||
db_manager = get_db_manager()
|
||||
|
||||
# 支持手机号或用户名登录
|
||||
sql = """
|
||||
SELECT u.id, u.enterprise_id, u.enterprise_name, u.username, u.phone, u.password,
|
||||
u.real_name, u.role, u.status, u.is_bound_xhs, a.xhs_account
|
||||
FROM ai_users u
|
||||
LEFT JOIN ai_authors a ON u.id = a.created_user_id AND a.status = 'active'
|
||||
WHERE (u.phone = %s OR u.username = %s) AND u.status = 'active'
|
||||
"""
|
||||
result = db_manager.execute_query(sql, (login_account, login_account))
|
||||
|
||||
if not result:
|
||||
logger.warning(f"[用户登录失败] 用户不存在或已禁用: {login_account}, IP: {client_ip}")
|
||||
return jsonify({
|
||||
'code': 401,
|
||||
'message': '账号或密码错误',
|
||||
'data': None
|
||||
}), 401
|
||||
|
||||
user = result[0]
|
||||
logger.info(f"[用户登录] 查询到用户信息, 用户名: {user['username']}, 角色: {user['role']}, 企业: {user['enterprise_name']}, 企业ID: {user['enterprise_id']}")
|
||||
|
||||
# 验证密码
|
||||
logger.info(f"[用户登录] 开始验证密码, 账号: {login_account}")
|
||||
if not AuthUtils.verify_password(password, user['password']):
|
||||
logger.warning(f"[用户登录失败] 密码错误: {login_account}, 用户名: {user['username']}, IP: {client_ip}")
|
||||
return jsonify({
|
||||
'code': 401,
|
||||
'message': '账号或密码错误',
|
||||
'data': None
|
||||
}), 401
|
||||
|
||||
logger.info(f"[用户登录] 密码验证成功, 用户名: {user['username']}, 角色: {user['role']}")
|
||||
|
||||
# 如果是企业角色,获取企业详细信息
|
||||
enterprise_info = None
|
||||
if user['role'] == 'enterprise' and user['enterprise_id']:
|
||||
logger.info(f"[用户登录] 检测到企业角色, 开始获取企业详细信息, 企业ID: {user['enterprise_id']}")
|
||||
enterprise_sql = """
|
||||
SELECT id, enterprise_ID, name, short_name, phone, email, status,
|
||||
users_total, products_total, articles_total, published_total
|
||||
FROM ai_enterprises
|
||||
WHERE id = %s AND status = 'active'
|
||||
"""
|
||||
enterprise_result = db_manager.execute_query(enterprise_sql, (user['enterprise_id'],))
|
||||
|
||||
if enterprise_result:
|
||||
enterprise_info = enterprise_result[0]
|
||||
logger.info(f"[用户登录] 获取企业信息成功, 企业名称: {enterprise_info['name']}, 企业编号: {enterprise_info['enterprise_ID']}")
|
||||
else:
|
||||
logger.warning(f"[用户登录] 企业信息不存在或已禁用, 企业ID: {user['enterprise_id']}")
|
||||
|
||||
# 生成token
|
||||
logger.info(f"[用户登录] 开始生成token, 用户ID: {user['id']}, 角色: {user['role']}")
|
||||
token = AuthUtils.generate_token(
|
||||
user['id'],
|
||||
user['phone'] or user['username'],
|
||||
user['role'],
|
||||
user['enterprise_id']
|
||||
)
|
||||
|
||||
# 构造返回数据
|
||||
user_info = {
|
||||
'id': user['id'],
|
||||
'name': user['real_name'] or user['username'],
|
||||
'username': user['username'],
|
||||
'phone': user['phone'],
|
||||
'role': user['role'],
|
||||
'enterpriseId': user['enterprise_id'],
|
||||
'enterpriseName': user['enterprise_name'],
|
||||
'isBoundXHS': bool(user.get('is_bound_xhs', 0)),
|
||||
'xhsAccount': user.get('xhs_account', '')
|
||||
}
|
||||
|
||||
# 如果是企业角色且有企业信息,添加企业详细信息
|
||||
if enterprise_info:
|
||||
user_info.update({
|
||||
'enterpriseCode': enterprise_info['enterprise_ID'],
|
||||
'enterpriseShortName': enterprise_info['short_name'],
|
||||
'enterpriseEmail': enterprise_info['email'],
|
||||
'enterprisePhone': enterprise_info['phone'],
|
||||
'usersTotal': enterprise_info['users_total'],
|
||||
'productsTotal': enterprise_info['products_total'],
|
||||
'articlesTotal': enterprise_info['articles_total'],
|
||||
'publishedTotal': enterprise_info['published_total']
|
||||
})
|
||||
|
||||
logger.info(f"[用户登录成功] Token生成成功, 用户: {user['username']}, 角色: {user['role']}, 企业: {user['enterprise_name']}, IP: {client_ip}")
|
||||
|
||||
# 返回用户信息和token
|
||||
return jsonify({
|
||||
'code': 200,
|
||||
'message': '登录成功',
|
||||
'data': {
|
||||
'token': token,
|
||||
'userInfo': user_info
|
||||
},
|
||||
'timestamp': int(datetime.now().timestamp() * 1000)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[用户登录处理] 处理请求时发生错误: {str(e)}", exc_info=True)
|
||||
return jsonify({
|
||||
'code': 500,
|
||||
'message': '服务器内部错误',
|
||||
'data': None
|
||||
}), 500
|
||||
|
||||
@auth_bp.route('/employee/login', methods=['POST'])
|
||||
def employee_login():
|
||||
"""员工登录"""
|
||||
client_ip = request.environ.get('HTTP_X_FORWARDED_FOR', request.environ.get('REMOTE_ADDR', '未知'))
|
||||
logger.info(f"[员工登录] 开始处理员工登录请求, IP: {client_ip}")
|
||||
|
||||
try:
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
logger.warning(f"[员工登录] 请求参数为空, IP: {client_ip}")
|
||||
return jsonify({
|
||||
'code': 400,
|
||||
'message': '请求参数错误',
|
||||
'data': None
|
||||
}), 400
|
||||
|
||||
phone = data.get('phone')
|
||||
password = data.get('password')
|
||||
|
||||
logger.info(f"[员工登录] 收到登录请求, 手机号: {phone}, IP: {client_ip}")
|
||||
|
||||
if not phone or not password:
|
||||
logger.warning(f"[员工登录] 手机号或密码为空, 手机号: {phone}, IP: {client_ip}")
|
||||
return jsonify({
|
||||
'code': 400,
|
||||
'message': '手机号和密码不能为空',
|
||||
'data': None
|
||||
}), 400
|
||||
|
||||
# 查询员工用户
|
||||
# 从ai_authors表获取xhs_account字段以优化性能
|
||||
logger.info(f"[员工登录] 开始查询员工信息, 手机号: {phone}")
|
||||
db_manager = get_db_manager()
|
||||
sql = """
|
||||
SELECT u.id, u.enterprise_id, u.real_name, u.phone, u.password, u.role, u.status,
|
||||
u.is_bound_xhs, a.xhs_account,
|
||||
e.name as enterprise_name
|
||||
FROM ai_users u
|
||||
LEFT JOIN ai_enterprises e ON u.enterprise_id = e.id
|
||||
LEFT JOIN ai_authors a ON u.id = a.created_user_id AND a.status = 'active'
|
||||
WHERE u.phone = %s
|
||||
"""
|
||||
result = db_manager.execute_query(sql, (phone,))
|
||||
|
||||
if not result:
|
||||
logger.warning(f"[员工登录失败] 用户不存在: {phone}, IP: {client_ip}")
|
||||
return jsonify({
|
||||
'code': 401,
|
||||
'message': '手机号或密码错误',
|
||||
'data': None
|
||||
}), 401
|
||||
|
||||
user = result[0]
|
||||
logger.info(f"[员工登录] 查询到员工信息, 姓名: {user['real_name']}, 角色: {user['role']}, 企业: {user['enterprise_name']}, 状态: {user['status']}, 绑定小红书: {user.get('is_bound_xhs', 0)}")
|
||||
|
||||
# 检查用户状态
|
||||
if user['status'] != 'active':
|
||||
logger.warning(f"[员工登录失败] 用户状态异常: {phone}, 状态: {user['status']}, 姓名: {user['real_name']}, IP: {client_ip}")
|
||||
return jsonify({
|
||||
'code': 403,
|
||||
'message': '用户已被禁用',
|
||||
'data': None
|
||||
}), 403
|
||||
|
||||
# 验证密码
|
||||
logger.info(f"[员工登录] 开始验证密码, 手机号: {phone}, 姓名: {user['real_name']}")
|
||||
if not AuthUtils.verify_password(password, user['password']):
|
||||
logger.warning(f"[员工登录失败] 密码错误: {phone}, 姓名: {user['real_name']}, IP: {client_ip}")
|
||||
return jsonify({
|
||||
'code': 401,
|
||||
'message': '手机号或密码错误',
|
||||
'data': None
|
||||
}), 401
|
||||
|
||||
# 生成token
|
||||
logger.info(f"[员工登录] 密码验证成功, 开始生成token, 姓名: {user['real_name']}, 角色: {user['role']}, 企业: {user['enterprise_name']}")
|
||||
token = AuthUtils.generate_token(user['id'], phone, user['role'], user['enterprise_id'])
|
||||
|
||||
logger.info(f"[员工登录成功] Token生成成功, 姓名: {user['real_name']}, 手机号: {phone}, 角色: {user['role']}, 企业: {user['enterprise_name']}, IP: {client_ip}")
|
||||
|
||||
# 返回用户信息和token
|
||||
return jsonify({
|
||||
'code': 200,
|
||||
'message': '登录成功',
|
||||
'data': {
|
||||
'token': token,
|
||||
'userInfo': {
|
||||
'id': user['id'],
|
||||
'name': user['real_name'],
|
||||
'phone': user['phone'],
|
||||
'role': user['role'],
|
||||
'enterpriseId': user['enterprise_id'],
|
||||
'enterpriseName': user['enterprise_name'],
|
||||
'isBoundXHS': bool(user.get('is_bound_xhs', 0)),
|
||||
'xhsAccount': user.get('xhs_account', '')
|
||||
}
|
||||
},
|
||||
'timestamp': int(datetime.now().timestamp() * 1000)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[员工登录处理] 处理请求时发生错误: {str(e)}", exc_info=True)
|
||||
return jsonify({
|
||||
'code': 500,
|
||||
'message': '服务器内部错误',
|
||||
'data': None
|
||||
}), 500
|
||||
|
||||
@auth_bp.route('/logout', methods=['POST'])
|
||||
def logout():
|
||||
"""用户登出"""
|
||||
try:
|
||||
# 记录登出日志
|
||||
auth_header = request.headers.get('Authorization')
|
||||
if auth_header:
|
||||
parts = auth_header.split()
|
||||
if len(parts) == 2:
|
||||
token = parts[1]
|
||||
payload = AuthUtils.verify_token(token)
|
||||
if payload:
|
||||
logger.info(f"[登出成功] 用户ID: {payload.get('user_id')}")
|
||||
|
||||
return jsonify({
|
||||
'code': 200,
|
||||
'message': '退出成功',
|
||||
'data': None,
|
||||
'timestamp': int(datetime.now().timestamp() * 1000)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[登出处理] 处理请求时发生错误: {str(e)}", exc_info=True)
|
||||
return jsonify({
|
||||
'code': 500,
|
||||
'message': '服务器内部错误',
|
||||
'data': None
|
||||
}), 500
|
||||
Reference in New Issue
Block a user