474 lines
14 KiB
C#
474 lines
14 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using UnityEngine;
|
||
|
||
/// <summary>
|
||
/// 持久化认证服务
|
||
/// 将用户数据保存到本地JSON文件,支持运行时增删改查
|
||
/// 使用 persistentDataPath 确保跨平台兼容性,特别是Android系统
|
||
/// </summary>
|
||
public class PersistentAuthenticationService : IAuthenticationService
|
||
{
|
||
private readonly string _dataFilePath;
|
||
private UserDatabase _userDatabase;
|
||
private const string DATA_FILE_NAME = "users.json";
|
||
private const int MAX_USER_COUNT = 10; // 最大用户数量限制
|
||
|
||
public bool IsLoggedIn { get; private set; }
|
||
public string CurrentUsername { get; private set; }
|
||
public UserRole CurrentRole { get; private set; }
|
||
public CurrentUser CurrentUser { get; private set; }
|
||
|
||
public PersistentAuthenticationService()
|
||
{
|
||
// 使用 persistentDataPath 而不是 streamingAssetsPath
|
||
// persistentDataPath 在所有平台上都是可读写的,包括 Android
|
||
_dataFilePath = Path.Combine(Application.persistentDataPath, DATA_FILE_NAME);
|
||
LoadUserDatabase();
|
||
Debug.Log($"用户数据存储路径: {_dataFilePath}");
|
||
}
|
||
|
||
public bool Login(string username, string password, out UserRole role)
|
||
{
|
||
role = UserRole.User;
|
||
|
||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
var user = _userDatabase.FindUser(username);
|
||
if (user != null && user.Password == password)
|
||
{
|
||
IsLoggedIn = true;
|
||
CurrentUsername = username;
|
||
CurrentRole = user.Role;
|
||
CurrentUser = new CurrentUser { Username = username, Role = user.Role };
|
||
role = user.Role;
|
||
|
||
// 更新最后登录时间
|
||
user.LastLoginTime = DateTime.Now;
|
||
SaveUserDatabase();
|
||
|
||
// 记录登录日志
|
||
var logService = ServiceLocator.Get<UserLogService>();
|
||
logService?.LogUserOperation(username, "用户登录", $"角色: {user.Role}", true);
|
||
|
||
Debug.Log($"用户 {username} 登录成功,角色: {user.Role}");
|
||
return true;
|
||
}
|
||
|
||
// 记录登录失败日志
|
||
var logServiceFailed = ServiceLocator.Get<UserLogService>();
|
||
logServiceFailed?.LogUserOperation(username, "用户登录", "密码错误或用户不存在", false);
|
||
|
||
IsLoggedIn = false;
|
||
CurrentUsername = null;
|
||
CurrentRole = UserRole.User;
|
||
CurrentUser = null;
|
||
return false;
|
||
}
|
||
|
||
public void Logout()
|
||
{
|
||
// 记录登出日志
|
||
if (!string.IsNullOrEmpty(CurrentUsername))
|
||
{
|
||
var logService = ServiceLocator.Get<UserLogService>();
|
||
logService?.LogUserOperation(CurrentUsername, "用户登出", "正常登出", true);
|
||
}
|
||
|
||
Debug.Log($"用户 {CurrentUsername} 登出");
|
||
IsLoggedIn = false;
|
||
CurrentUsername = null;
|
||
CurrentRole = UserRole.User;
|
||
CurrentUser = null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加新用户
|
||
/// </summary>
|
||
public bool AddUser(string username, string password, UserRole role)
|
||
{
|
||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
|
||
{
|
||
Debug.LogError("用户名和密码不能为空");
|
||
return false;
|
||
}
|
||
|
||
// 检查用户数量限制
|
||
if (_userDatabase.Users.Count >= MAX_USER_COUNT)
|
||
{
|
||
Debug.LogError($"用户数量已达到上限({MAX_USER_COUNT}个),无法添加新用户");
|
||
return false;
|
||
}
|
||
|
||
// 验证用户名格式(只允许字母、数字和下划线,区分大小写)
|
||
if (!IsValidUsername(username))
|
||
{
|
||
Debug.LogError("用户名只能包含字母、数字和下划线,不允许特殊字符");
|
||
return false;
|
||
}
|
||
|
||
// 检查用户是否已存在(区分大小写)
|
||
if (_userDatabase.FindUser(username) != null)
|
||
{
|
||
Debug.LogError($"用户 {username} 已存在");
|
||
return false;
|
||
}
|
||
|
||
var newUser = new UserInfo
|
||
{
|
||
Username = username,
|
||
Password = password,
|
||
Role = role,
|
||
CreatedTime = DateTime.Now,
|
||
IsActive = true
|
||
};
|
||
|
||
_userDatabase.Users.Add(newUser);
|
||
SaveUserDatabase();
|
||
|
||
// 记录添加用户日志
|
||
var logService = ServiceLocator.Get<UserLogService>();
|
||
logService?.LogUserOperation(CurrentUsername ?? "system", "添加用户",
|
||
$"新用户: {username}, 角色: {role}", true);
|
||
|
||
Debug.Log($"成功添加用户 {username},角色: {role}");
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除用户
|
||
/// </summary>
|
||
public bool RemoveUser(string username)
|
||
{
|
||
if (string.IsNullOrEmpty(username))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 不能删除admin用户(区分大小写)
|
||
if (username == "admin")
|
||
{
|
||
Debug.LogError("不能删除管理员账户");
|
||
return false;
|
||
}
|
||
|
||
// 不能删除当前登录用户(区分大小写)
|
||
if (username == CurrentUsername)
|
||
{
|
||
Debug.LogError("不能删除当前登录用户");
|
||
return false;
|
||
}
|
||
|
||
var user = _userDatabase.FindUser(username);
|
||
if (user != null)
|
||
{
|
||
_userDatabase.Users.Remove(user);
|
||
SaveUserDatabase();
|
||
|
||
// 记录删除用户日志
|
||
var logService = ServiceLocator.Get<UserLogService>();
|
||
logService?.LogUserOperation(CurrentUsername ?? "system", "删除用户",
|
||
$"删除用户: {username}, 角色: {user.Role}", true);
|
||
|
||
Debug.Log($"成功删除用户 {username}");
|
||
return true;
|
||
}
|
||
|
||
Debug.LogError($"用户 {username} 不存在");
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 修改用户密码 - 支持管理员重置和用户自改密码
|
||
/// </summary>
|
||
public bool ChangePassword(string username, string oldPassword, string newPassword)
|
||
{
|
||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(newPassword))
|
||
{
|
||
Debug.LogError("用户名和新密码不能为空");
|
||
return false;
|
||
}
|
||
|
||
var user = _userDatabase.FindUser(username);
|
||
if (user == null)
|
||
{
|
||
Debug.LogError($"用户 {username} 不存在");
|
||
return false;
|
||
}
|
||
|
||
// 检查操作权限(区分大小写)
|
||
bool isAdmin = CurrentRole == UserRole.Admin;
|
||
bool isSelfChange = username == CurrentUsername;
|
||
|
||
// 如果是管理员操作且不是修改自己的密码,可以跳过旧密码验证
|
||
if (isAdmin && !isSelfChange)
|
||
{
|
||
user.Password = newPassword;
|
||
user.PasswordChangedTime = DateTime.Now;
|
||
SaveUserDatabase();
|
||
|
||
// 记录管理员重置密码日志
|
||
var logService = ServiceLocator.Get<UserLogService>();
|
||
logService?.LogUserOperation(CurrentUsername, "重置用户密码",
|
||
$"管理员重置用户 {username} 的密码", true);
|
||
|
||
Debug.Log($"管理员重置用户 {username} 密码成功");
|
||
return true;
|
||
}
|
||
|
||
// 其他情况需要验证旧密码
|
||
if (string.IsNullOrEmpty(oldPassword))
|
||
{
|
||
Debug.LogError("修改密码需要提供旧密码");
|
||
return false;
|
||
}
|
||
|
||
if (user.Password != oldPassword)
|
||
{
|
||
Debug.LogError("旧密码错误");
|
||
return false;
|
||
}
|
||
|
||
user.Password = newPassword;
|
||
user.PasswordChangedTime = DateTime.Now;
|
||
SaveUserDatabase();
|
||
|
||
// 记录修改密码日志
|
||
var logService2 = ServiceLocator.Get<UserLogService>();
|
||
logService2?.LogUserOperation(username, "修改密码",
|
||
isSelfChange ? "用户修改自己的密码" : $"修改用户 {username} 的密码", true);
|
||
|
||
Debug.Log($"用户 {username} 密码修改成功");
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有用户信息(不包含密码)
|
||
/// </summary>
|
||
public List<UserInfo> GetAllUsers()
|
||
{
|
||
var result = new List<UserInfo>();
|
||
foreach (var user in _userDatabase.Users)
|
||
{
|
||
result.Add(new UserInfo
|
||
{
|
||
Username = user.Username,
|
||
Role = user.Role,
|
||
CreatedTime = user.CreatedTime,
|
||
LastLoginTime = user.LastLoginTime,
|
||
IsActive = user.IsActive
|
||
// 不返回密码信息
|
||
});
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载用户数据库
|
||
/// </summary>
|
||
private void LoadUserDatabase()
|
||
{
|
||
try
|
||
{
|
||
if (File.Exists(_dataFilePath))
|
||
{
|
||
string json = File.ReadAllText(_dataFilePath);
|
||
_userDatabase = JsonUtility.FromJson<UserDatabase>(json);
|
||
|
||
if (_userDatabase == null || _userDatabase.Users == null)
|
||
{
|
||
Debug.LogWarning("用户数据库格式错误,创建新的数据库");
|
||
CreateDefaultUserDatabase();
|
||
}
|
||
else
|
||
{
|
||
Debug.Log($"成功加载用户数据库,共 {_userDatabase.Users.Count} 个用户");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 创建默认用户数据库
|
||
CreateDefaultUserDatabase();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogError($"加载用户数据库失败: {ex.Message}");
|
||
CreateDefaultUserDatabase();
|
||
}
|
||
|
||
// 确保数据库不为空
|
||
if (_userDatabase == null)
|
||
{
|
||
CreateDefaultUserDatabase();
|
||
}
|
||
}
|
||
|
||
public bool ValidCurrentPassword(string password)
|
||
{
|
||
if (CurrentUser != null && CurrentUser.Username != null)
|
||
{
|
||
var user = _userDatabase.FindUser(CurrentUser.Username);
|
||
if (user != null && user.Password == password)
|
||
{
|
||
Debug.Log("当前密码验证成功");
|
||
return true;
|
||
}
|
||
}
|
||
|
||
Debug.Log("当前密码验证失败");
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存用户数据库
|
||
/// </summary>
|
||
private void SaveUserDatabase()
|
||
{
|
||
try
|
||
{
|
||
// 确保目录存在(persistentDataPath 通常已存在,但为了安全起见还是检查一下)
|
||
string directory = Path.GetDirectoryName(_dataFilePath);
|
||
if (!Directory.Exists(directory))
|
||
{
|
||
Directory.CreateDirectory(directory);
|
||
}
|
||
|
||
string json = JsonUtility.ToJson(_userDatabase, true);
|
||
File.WriteAllText(_dataFilePath, json);
|
||
Debug.Log($"用户数据库保存成功到: {_dataFilePath}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogError($"保存用户数据库失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建默认用户数据库
|
||
/// </summary>
|
||
private void CreateDefaultUserDatabase()
|
||
{
|
||
_userDatabase = new UserDatabase
|
||
{
|
||
Version = "1.0",
|
||
Users = new List<UserInfo>
|
||
{
|
||
new UserInfo
|
||
{
|
||
Username = "admin",
|
||
Password = "admin",
|
||
Role = UserRole.Admin,
|
||
CreatedTime = DateTime.Now,
|
||
IsActive = true
|
||
},
|
||
new UserInfo
|
||
{
|
||
Username = "user",
|
||
Password = "123456",
|
||
Role = UserRole.User,
|
||
CreatedTime = DateTime.Now,
|
||
IsActive = true
|
||
}
|
||
}
|
||
};
|
||
|
||
SaveUserDatabase();
|
||
Debug.Log("创建默认用户数据库");
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证用户名格式
|
||
/// 只允许字母、数字和下划线,长度3-20个字符
|
||
/// </summary>
|
||
private bool IsValidUsername(string username)
|
||
{
|
||
if (string.IsNullOrEmpty(username))
|
||
return false;
|
||
|
||
// 长度限制
|
||
if (username.Length < 3 || username.Length > 20)
|
||
{
|
||
Debug.LogError("用户名长度必须在3-20个字符之间");
|
||
return false;
|
||
}
|
||
|
||
// 只允许字母、数字和下划线
|
||
foreach (char c in username)
|
||
{
|
||
if (!char.IsLetterOrDigit(c) && c != '_')
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前用户数量
|
||
/// </summary>
|
||
public int GetUserCount()
|
||
{
|
||
return _userDatabase?.Users?.Count ?? 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取最大用户数量限制
|
||
/// </summary>
|
||
public int GetMaxUserCount()
|
||
{
|
||
return MAX_USER_COUNT;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取数据文件路径(用于调试)
|
||
/// </summary>
|
||
public string GetDataFilePath()
|
||
{
|
||
return _dataFilePath;
|
||
}
|
||
}
|
||
|
||
// /// <summary>
|
||
// /// 用户数据库结构
|
||
// /// </summary>
|
||
// [System.Serializable]
|
||
// public class UserDatabase
|
||
// {
|
||
// public string Version = "1.0";
|
||
// public List<UserInfo> Users = new List<UserInfo>();
|
||
|
||
// public UserInfo FindUser(string username)
|
||
// {
|
||
// return Users.Find(u => u.Username.Equals(username, StringComparison.OrdinalIgnoreCase) && u.IsActive);
|
||
// }
|
||
// }
|
||
|
||
// /// <summary>
|
||
// /// 用户信息扩展
|
||
// /// </summary>
|
||
// [System.Serializable]
|
||
// public class UserInfo
|
||
// {
|
||
// public string Username;
|
||
// public string Password;
|
||
// public UserRole Role;
|
||
// public DateTime CreatedTime;
|
||
// public DateTime LastLoginTime;
|
||
// public DateTime PasswordChangedTime;
|
||
// public bool IsActive = true;
|
||
// }
|
||
|
||
// public class UseLogEvent
|
||
// {
|
||
// public int Id;
|
||
// public string OperationContentText;
|
||
// public DateTime Time;
|
||
// public string Account;
|
||
// } |