refactor: 移除冗余文件并优化代码结构
- 删除多个不再使用的脚本和配置文件,包括 `auto_push.bat`, `check_and_fix_users.py`, `init.sql` 等。 - 新增 `git_push.bat` 和 `git_push.sh` 脚本以简化 Git 推送流程。 - 更新 `README.md` 以反映最新的功能和结构变化。 - 优化前端代码,添加新的页面和组件,提升用户体验。 此提交旨在清理项目结构并增强代码可维护性。
This commit is contained in:
Binary file not shown.
BIN
src/core/__pycache__/auth_manager.cpython-311.pyc
Normal file
BIN
src/core/__pycache__/auth_manager.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
144
src/core/auth_manager.py
Normal file
144
src/core/auth_manager.py
Normal file
@@ -0,0 +1,144 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
认证管理器
|
||||
处理用户登录、注册、会话管理等功能
|
||||
"""
|
||||
|
||||
import jwt
|
||||
import hashlib
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional, Dict, Any
|
||||
from flask import current_app
|
||||
|
||||
from src.core.database import db_manager
|
||||
from src.core.models import User
|
||||
|
||||
|
||||
class AuthManager:
|
||||
"""认证管理器"""
|
||||
|
||||
def __init__(self):
|
||||
self.secret_key = "your-secret-key-change-this-in-production" # 应该从配置中读取
|
||||
self.token_expiry = timedelta(hours=24)
|
||||
|
||||
def hash_password(self, password: str) -> str:
|
||||
"""密码哈希"""
|
||||
return hashlib.sha256(password.encode()).hexdigest()
|
||||
|
||||
def verify_password(self, password: str, password_hash: str) -> bool:
|
||||
"""验证密码"""
|
||||
return self.hash_password(password) == password_hash
|
||||
|
||||
def generate_token(self, user_data: dict) -> str:
|
||||
"""生成JWT token"""
|
||||
payload = {
|
||||
'user_id': user_data['id'],
|
||||
'username': user_data['username'],
|
||||
'exp': datetime.utcnow() + self.token_expiry,
|
||||
'iat': datetime.utcnow()
|
||||
}
|
||||
return jwt.encode(payload, self.secret_key, algorithm='HS256')
|
||||
|
||||
def verify_token(self, token: str) -> Optional[Dict[str, Any]]:
|
||||
"""验证JWT token"""
|
||||
try:
|
||||
payload = jwt.decode(token, self.secret_key, algorithms=['HS256'])
|
||||
return payload
|
||||
except jwt.ExpiredSignatureError:
|
||||
return None
|
||||
except jwt.InvalidTokenError:
|
||||
return None
|
||||
|
||||
def authenticate_user(self, username: str, password: str) -> Optional[dict]:
|
||||
"""用户认证"""
|
||||
print(f"[DEBUG] 开始认证用户: {username}")
|
||||
with db_manager.get_session() as session:
|
||||
user = session.query(User).filter_by(username=username).first()
|
||||
print(f"[DEBUG] 找到用户: {user is not None}")
|
||||
|
||||
if user and user.is_active and self.verify_password(password, user.password_hash):
|
||||
print(f"[DEBUG] 用户认证成功: {user.username}")
|
||||
|
||||
# 立即访问所有需要的属性,确保在会话内
|
||||
user_id = user.id
|
||||
username_val = user.username
|
||||
password_hash_val = user.password_hash
|
||||
email_val = user.email
|
||||
name_val = user.name
|
||||
role_val = user.role
|
||||
is_active_val = user.is_active
|
||||
created_at_val = user.created_at
|
||||
last_login_val = datetime.now()
|
||||
|
||||
print(f"[DEBUG] 访问用户属性成功: name={name_val}, role={role_val}")
|
||||
|
||||
# 更新最后登录时间
|
||||
user.last_login = last_login_val
|
||||
session.commit()
|
||||
print("[DEBUG] 数据库更新成功")
|
||||
|
||||
# 返回用户数据字典,避免SQLAlchemy会话绑定问题
|
||||
user_dict = {
|
||||
'id': user_id,
|
||||
'username': username_val,
|
||||
'password_hash': password_hash_val,
|
||||
'email': email_val,
|
||||
'name': name_val,
|
||||
'role': role_val,
|
||||
'is_active': is_active_val,
|
||||
'created_at': created_at_val,
|
||||
'last_login': last_login_val
|
||||
}
|
||||
print(f"[DEBUG] 返回用户字典: {user_dict['username']}")
|
||||
return user_dict
|
||||
else:
|
||||
print("[DEBUG] 用户认证失败")
|
||||
return None
|
||||
|
||||
def get_user_by_id(self, user_id: int) -> Optional[User]:
|
||||
"""根据ID获取用户"""
|
||||
with db_manager.get_session() as session:
|
||||
return session.query(User).filter_by(id=user_id).first()
|
||||
|
||||
def get_user_by_token(self, token: str) -> Optional[User]:
|
||||
"""根据token获取用户"""
|
||||
payload = self.verify_token(token)
|
||||
if payload:
|
||||
return self.get_user_by_id(payload['user_id'])
|
||||
return None
|
||||
|
||||
def create_user(self, username: str, password: str, name: str, email: str = None, role: str = 'user') -> Optional[User]:
|
||||
"""创建新用户"""
|
||||
try:
|
||||
with db_manager.get_session() as session:
|
||||
# 检查用户名是否已存在
|
||||
existing_user = session.query(User).filter_by(username=username).first()
|
||||
if existing_user:
|
||||
return None
|
||||
|
||||
user = User(
|
||||
username=username,
|
||||
name=name,
|
||||
email=email,
|
||||
role=role,
|
||||
is_active=True
|
||||
)
|
||||
user.set_password(password)
|
||||
|
||||
session.add(user)
|
||||
session.commit()
|
||||
return user
|
||||
except Exception as e:
|
||||
print(f"创建用户失败: {e}")
|
||||
return None
|
||||
|
||||
def create_default_admin(self):
|
||||
"""创建默认管理员用户"""
|
||||
admin = self.create_user('admin', 'admin123', '系统管理员', 'admin@example.com', 'admin')
|
||||
if admin:
|
||||
print("默认管理员用户已创建: admin/admin123")
|
||||
return admin
|
||||
|
||||
|
||||
# 全局认证管理器实例
|
||||
auth_manager = AuthManager()
|
||||
@@ -26,18 +26,22 @@ class DatabaseManager:
|
||||
|
||||
# 根据数据库类型选择不同的连接参数
|
||||
if "mysql" in db_config["url"]:
|
||||
# MySQL配置 - 优化连接池
|
||||
# MySQL配置 - 优化连接池和重连机制
|
||||
self.engine = create_engine(
|
||||
db_config["url"],
|
||||
echo=db_config["echo"],
|
||||
pool_size=20, # 增加连接池大小
|
||||
max_overflow=30, # 增加溢出连接数
|
||||
pool_pre_ping=True,
|
||||
pool_recycle=1800, # 减少回收时间
|
||||
pool_timeout=30, # 连接池超时(秒)
|
||||
pool_size=10, # 连接池大小
|
||||
max_overflow=20, # 溢出连接数
|
||||
pool_pre_ping=True, # 连接前检查连接是否有效
|
||||
pool_recycle=3600, # 1小时后回收连接
|
||||
pool_timeout=60, # 连接池超时(秒)
|
||||
connect_args={
|
||||
"charset": "utf8mb4",
|
||||
"autocommit": False,
|
||||
"connect_timeout": 30, # 连接超时
|
||||
"read_timeout": 60, # 读取超时
|
||||
"write_timeout": 60, # 写入超时
|
||||
"max_allowed_packet": 64*1024*1024, # 64MB
|
||||
"connect_timeout": 30, # 连接超时(秒)- 适用于网络延迟较大的情况
|
||||
"read_timeout": 30, # 读取超时(秒)
|
||||
"write_timeout": 30, # 写入超时(秒)
|
||||
@@ -82,7 +86,32 @@ class DatabaseManager:
|
||||
logger.error(f"数据库操作失败: {e}")
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
try:
|
||||
session.close()
|
||||
except Exception as close_error:
|
||||
logger.warning(f"关闭数据库会话时出错: {close_error}")
|
||||
|
||||
def check_connection(self) -> bool:
|
||||
"""检查数据库连接是否正常"""
|
||||
try:
|
||||
with self.get_session() as session:
|
||||
session.execute(text("SELECT 1"))
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"数据库连接检查失败: {e}")
|
||||
return False
|
||||
|
||||
def reconnect(self) -> bool:
|
||||
"""重新连接数据库"""
|
||||
try:
|
||||
if self.engine:
|
||||
self.engine.dispose()
|
||||
self._initialize_database()
|
||||
logger.info("数据库重新连接成功")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"数据库重新连接失败: {e}")
|
||||
return False
|
||||
|
||||
def get_session_direct(self) -> Session:
|
||||
"""直接获取数据库会话"""
|
||||
|
||||
@@ -2,6 +2,7 @@ from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean,
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
import hashlib
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
@@ -173,3 +174,39 @@ class WorkOrderProcessHistory(Base):
|
||||
|
||||
# 关联工单
|
||||
work_order = relationship("WorkOrder", back_populates="process_history")
|
||||
|
||||
|
||||
class User(Base):
|
||||
"""用户模型"""
|
||||
__tablename__ = "users"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
username = Column(String(50), unique=True, nullable=False)
|
||||
password_hash = Column(String(128), nullable=False)
|
||||
email = Column(String(120), unique=True, nullable=True)
|
||||
name = Column(String(100), nullable=True)
|
||||
role = Column(String(20), default='user') # admin, user, operator
|
||||
is_active = Column(Boolean, default=True)
|
||||
created_at = Column(DateTime, default=datetime.now)
|
||||
last_login = Column(DateTime)
|
||||
|
||||
def set_password(self, password):
|
||||
"""设置密码哈希"""
|
||||
self.password_hash = hashlib.sha256(password.encode()).hexdigest()
|
||||
|
||||
def check_password(self, password):
|
||||
"""验证密码"""
|
||||
return self.password_hash == hashlib.sha256(password.encode()).hexdigest()
|
||||
|
||||
def to_dict(self):
|
||||
"""转换为字典格式(用于API响应)"""
|
||||
return {
|
||||
'id': self.id,
|
||||
'username': self.username,
|
||||
'email': self.email,
|
||||
'name': self.name,
|
||||
'role': self.role,
|
||||
'is_active': self.is_active,
|
||||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||||
'last_login': self.last_login.isoformat() if self.last_login else None
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ class QueryOptimizer:
|
||||
# 处理状态映射(支持中英文状态)
|
||||
status_mapping = {
|
||||
'open': ['open', '待处理', '新建', 'new'],
|
||||
'in_progress': ['in_progress', '处理中', '进行中', 'progress', 'processing'],
|
||||
'in_progress': ['in_progress', '处理中', '进行中', 'progress', 'processing', 'analysising', 'analyzing'],
|
||||
'resolved': ['resolved', '已解决', '已完成'],
|
||||
'closed': ['closed', '已关闭', '关闭']
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user