config_editor/login.py

240 lines
8.8 KiB
Python
Raw Normal View History

2026-01-19 08:02:47 +00:00
'''用户认证登录模块'''
import json
import os
import datetime
from pathlib import Path
from typing import Tuple, Optional
class SimpleAuth:
"""用户认证管理器"""
def __init__(self, config_path: str = None):
"""
初始化认证管理器
Args:
config_path: 用户配置文件路径
"""
self.config_path = config_path
self.users = {}
# 初始化时加载用户数据
if config_path:
self.load_users()
def load_users(self) -> bool:
"""加载用户数据"""
try:
if not self.config_path:
print("未设置配置文件路径")
return False
# 如果文件不存在,创建空文件
if not os.path.exists(self.config_path):
print(f"配置文件不存在,创建空文件: {self.config_path}")
return self.create_empty_file()
# 读取文件内容
with open(self.config_path, 'r', encoding='utf-8') as f:
content = f.read().strip()
if not content: # 空文件
self.users = {}
return True
# 解析JSON
self.users = json.loads(content)
print(f"已加载 {len(self.users)} 个用户")
return True
except json.JSONDecodeError:
print("配置文件格式错误,重置为空文件")
return self.create_empty_file()
except Exception as e:
print(f"加载用户数据失败: {e}")
return False
def create_empty_file(self) -> bool:
"""创建空的配置文件"""
try:
if not self.config_path:
return False
os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
self.users = {}
with open(self.config_path, 'w', encoding='utf-8') as f:
json.dump({}, f, indent=2, ensure_ascii=False)
print(f"已创建空白配置文件: {self.config_path}")
return True
except Exception as e:
print(f"创建配置文件失败: {e}")
return False
def save_users(self) -> bool:
"""保存用户数据"""
try:
if not self.config_path:
return False
os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
with open(self.config_path, 'w', encoding='utf-8') as f:
json.dump(self.users, f, indent=2, ensure_ascii=False)
return True
except Exception as e:
print(f"保存用户数据失败: {e}")
return False
def authenticate(self, username: str, password: str) -> Tuple[bool, str]:
"""
验证用户凭据
重要如果用户不存在则创建用户首次登录即注册
"""
if not username or not password:
return False, "用户名和密码不能为空"
# 加载用户数据
if not self.load_users():
return False, "加载用户数据失败"
# 检查用户名是否存在(作为字典键)
if username not in self.users:
# 首次登录,自动创建用户
print(f"用户 '{username}' 不存在,首次登录将自动创建用户")
return self.create_first_user(username, password)
# 检查密码是否正确
user_info = self.users[username]
if user_info.get("password") != password:
return False, "密码错误"
# 更新最后登录时间
user_info["last_login"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.save_users()
return True, "登录成功"
def create_first_user(self, username: str, password: str) -> Tuple[bool, str]:
"""创建第一个用户(首次登录)"""
try:
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 创建用户信息
self.users[username] = {
"username": username,
"password": password,
"secondary_password": "", # 二级密码初始为空,首次登录后设置
"created_at": current_time,
"last_login": current_time,
"is_first_user": True
}
# 保存用户数据
if self.save_users():
print(f"已创建用户 '{username}' 并登录")
return True, f"首次登录成功,已创建用户 '{username}'"
else:
return False, "创建用户失败"
except Exception as e:
print(f"创建用户失败: {e}")
return False, f"创建用户失败: {str(e)}"
def set_secondary_password(self, username: str, secondary_password: str) -> Tuple[bool, str]:
"""设置二级密码"""
try:
if not self.load_users():
return False, "加载用户数据失败"
if username not in self.users:
return False, "用户不存在"
if not secondary_password:
return False, "二级密码不能为空"
# 更新二级密码
self.users[username]["secondary_password"] = secondary_password
self.users[username]["secondary_password_updated_at"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if self.save_users():
return True, "二级密码设置成功"
else:
return False, "保存二级密码失败"
except Exception as e:
return False, f"设置二级密码失败: {str(e)}"
def verify_secondary_password(self, username: str, secondary_password: str) -> Tuple[bool, str]:
"""验证二级密码"""
try:
if not self.load_users():
return False, "加载用户数据失败"
if username not in self.users:
return False, "用户不存在"
user_info = self.users[username]
# 检查用户是否设置了二级密码
if not user_info.get("secondary_password"):
return False, "未设置二级密码,请先设置"
# 验证二级密码
if user_info.get("secondary_password") != secondary_password:
return False, "二级密码错误"
return True, "二级密码验证成功"
except Exception as e:
return False, f"验证二级密码失败: {str(e)}"
def get_secondary_password_status(self, username: str) -> Tuple[bool, str]:
"""获取二级密码设置状态"""
try:
if not self.load_users():
return False, "加载用户数据失败"
if username not in self.users:
return False, "用户不存在"
user_info = self.users[username]
if user_info.get("secondary_password"):
return True, f"已设置二级密码(更新于: {user_info.get('secondary_password_updated_at', '未知时间')}"
else:
return False, "未设置二级密码"
except Exception as e:
return False, f"获取二级密码状态失败: {str(e)}"
def get_default_config_path(self) -> str:
"""获取默认配置文件路径"""
return str(Path.home() / ".config_editor" / "users.json")
@staticmethod
def validate_config_path(config_path: str) -> bool:
"""验证配置文件路径是否有效"""
try:
# 检查路径是否包含有效的目录
dir_path = os.path.dirname(config_path)
if not dir_path:
return False
# 检查是否是绝对路径
if not os.path.isabs(config_path):
return False
# 检查文件扩展名(可选)
if not config_path.endswith(('.json', '.txt', '.dat')):
return False
return True
except Exception:
return False