#include "stdafx.h"
|
#include "UserManager.h"
|
#include <chrono>
|
#include <iostream>
|
#include <fstream>
|
#include <ctime>
|
#include <sstream>
|
|
const std::string SESSION_FILE = R"(session.dat)";
|
const std::string DATABASE_FILE = R"(UserManager.db)";
|
|
const std::string INITIAL_ADMIN_USERNAME = "admin";
|
const std::string INITIAL_ADMIN_PASSWORD = "admin";
|
|
// 获取单例实例
|
UserManager& UserManager::getInstance() {
|
static UserManager instance;
|
return instance;
|
}
|
|
UserManager::UserManager()
|
: m_isLoggedIn(false), m_isRememberMe(false), m_tmSessionTimeout(std::chrono::minutes(30)),
|
m_tmSessionExpiration(std::chrono::hours(72)), m_hMouseHook(nullptr), m_hKeyboardHook(nullptr),
|
m_pDB(std::make_unique<BL::SQLiteDatabase>()) {
|
initializeDatabase();
|
}
|
|
UserManager::~UserManager() {
|
terminateIdleDetection();
|
}
|
|
// 提供数据库连接
|
std::unique_ptr<BL::Database>& UserManager::getDatabaseInstance() {
|
return m_pDB;
|
}
|
|
// 初始化数据库,创建用户表并插入初始管理员用户
|
bool UserManager::initializeDatabase() {
|
std::string dbFilePath = getDatabaseFilePath();
|
if (!m_pDB->connect(dbFilePath, true)) {
|
throw std::runtime_error("Failed to connect to database.");
|
}
|
|
std::string createTableQuery = R"(
|
CREATE TABLE IF NOT EXISTS users (
|
username VARCHAR(50) PRIMARY KEY,
|
password VARCHAR(255) NOT NULL,
|
role INT NOT NULL,
|
session_timeout INT DEFAULT 30,
|
session_expiration INT DEFAULT 72,
|
last_login DATETIME DEFAULT (datetime('now', 'localtime'))
|
)
|
)";
|
m_pDB->executeQuery(createTableQuery);
|
|
std::string checkAdminQuery = "SELECT COUNT(*) FROM users WHERE role = 0";
|
auto result = m_pDB->fetchResults(checkAdminQuery);
|
|
if (result.empty() || result[0][0] == "0") {
|
std::string insertAdminQuery = "INSERT INTO users (username, password, role, session_timeout, session_expiration) VALUES ('" +
|
INITIAL_ADMIN_USERNAME + "', '" + simpleEncryptDecrypt(INITIAL_ADMIN_PASSWORD, "BandKey") + "', 0, 30, 72)";
|
m_pDB->executeQuery(insertAdminQuery);
|
}
|
|
return true;
|
}
|
|
// 对密码进行哈希处理
|
std::string UserManager::hashPassword(const std::string& password) {
|
return std::to_string(std::hash<std::string>{}(password));
|
}
|
|
// 简单的加密和解密函数
|
std::string UserManager::simpleEncryptDecrypt(const std::string& data, const std::string& key) {
|
std::string result = data;
|
for (size_t i = 0; i < data.size(); ++i) {
|
result[i] ^= key[i % key.size()]; // 简单异或加密
|
}
|
return result;
|
}
|
|
// 从会话文件加载会话信息
|
bool UserManager::loadSession() {
|
std::ifstream sessionFile(getSessionFilePath(), std::ios::binary);
|
if (!sessionFile.is_open()) {
|
return false;
|
}
|
|
// 从文件读取加密数据
|
std::string encryptedData((std::istreambuf_iterator<char>(sessionFile)), std::istreambuf_iterator<char>());
|
sessionFile.close();
|
|
// 解密数据
|
std::string decryptedData = simpleEncryptDecrypt(encryptedData, "my_secret_key");
|
|
// 解析解密的数据
|
std::istringstream sessionData(decryptedData);
|
std::string username;
|
std::string password;
|
std::time_t lastLoginTime;
|
int timeoutMinutes;
|
int expirationHours;
|
|
sessionData >> username >> password >> lastLoginTime >> timeoutMinutes >> expirationHours;
|
|
// 验证时间戳有效性
|
auto now = std::chrono::system_clock::now();
|
auto lastLogin = std::chrono::system_clock::from_time_t(lastLoginTime);
|
auto sessionDuration = std::chrono::duration_cast<std::chrono::hours>(now - lastLogin);
|
|
if (sessionDuration > std::chrono::hours(expirationHours)) {
|
clearSession();
|
return false;
|
}
|
|
// 恢复会话数据
|
m_strCurrentUser = username;
|
m_strCurrentPass = password;
|
m_tpLastLogin = lastLogin;
|
m_tmSessionTimeout = std::chrono::minutes(timeoutMinutes);
|
m_tmSessionExpiration = std::chrono::hours(expirationHours);
|
m_isLoggedIn = true;
|
m_isRememberMe = true;
|
updateActivityTime();
|
|
return true;
|
}
|
|
// 保存会话信息到文件
|
void UserManager::saveSession() {
|
if (!m_isRememberMe) {
|
clearSession();
|
return;
|
}
|
|
// 原始会话数据
|
std::stringstream sessionData;
|
std::time_t lastLoginTime = std::chrono::system_clock::to_time_t(m_tpLastLogin);
|
sessionData << m_strCurrentUser << " " << m_strCurrentPass << " " << lastLoginTime << " "
|
<< m_tmSessionTimeout.count() << " " << m_tmSessionExpiration.count();
|
|
// 加密数据
|
std::string encryptedData = simpleEncryptDecrypt(sessionData.str(), "my_secret_key");
|
|
// 写入加密数据到文件
|
std::ofstream sessionFile(getSessionFilePath(), std::ios::binary);
|
if (sessionFile.is_open()) {
|
sessionFile << encryptedData;
|
sessionFile.close();
|
}
|
}
|
|
// 清除会话文件
|
void UserManager::clearSession() {
|
std::remove(getSessionFilePath().c_str());
|
}
|
|
// 获取程序路径下的config文件夹路径
|
std::string UserManager::getConfigFolderPath() {
|
char szPath[MAX_PATH];
|
GetModuleFileName(NULL, szPath, MAX_PATH);
|
std::string exePath(szPath);
|
std::string dbDir = exePath.substr(0, exePath.find_last_of("\\/")) + "\\DB\\";
|
|
// 检查并创建config文件夹
|
DWORD fileAttr = GetFileAttributes(dbDir.c_str());
|
if (fileAttr == INVALID_FILE_ATTRIBUTES) {
|
CreateDirectory(dbDir.c_str(), NULL);
|
}
|
|
return dbDir;
|
}
|
|
// 获取session.dat文件路径
|
std::string UserManager::getSessionFilePath() {
|
return getConfigFolderPath() + SESSION_FILE;
|
}
|
|
// 获取数据库文件路径
|
std::string UserManager::getDatabaseFilePath() {
|
return getConfigFolderPath() + DATABASE_FILE;
|
}
|
|
// 登录方法
|
bool UserManager::login(const std::string& username, const std::string& password, bool rememberMeFlag) {
|
std::string query = "SELECT username, password, role, session_timeout, session_expiration FROM users WHERE username = '" + username + "'";
|
auto result = m_pDB->fetchResults(query);
|
|
if (result.empty() || result[0][1] != simpleEncryptDecrypt(password, "BandKey")) {
|
std::cerr << "Login failed: Invalid username or password." << std::endl;
|
return false;
|
}
|
|
m_strCurrentUser = username;
|
m_strCurrentPass = password;
|
m_enCurrentUserRole = static_cast<UserRole>(std::stoi(result[0][2]));
|
m_tmSessionTimeout = std::chrono::minutes(std::stoi(result[0][3]));
|
m_tmSessionExpiration = std::chrono::hours(std::stoi(result[0][4]));
|
m_isLoggedIn = true;
|
m_isRememberMe = rememberMeFlag;
|
updateActivityTime();
|
m_tpLastLogin = std::chrono::system_clock::now();
|
|
std::string updateLoginTime = "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE username = '" + username + "'";
|
m_pDB->executeQuery(updateLoginTime);
|
|
saveSession();
|
return true;
|
}
|
|
// 登出方法
|
void UserManager::logout() {
|
if (m_isLoggedIn) {
|
std::cout << "User logged out: " << m_strCurrentUser << std::endl;
|
m_strCurrentUser.clear();
|
m_strCurrentPass.clear();
|
m_isLoggedIn = false;
|
m_isRememberMe = false;
|
clearSession();
|
}
|
}
|
|
// 返回当前用户的登录状态
|
bool UserManager::isLoggedIn() const {
|
return m_isLoggedIn;
|
}
|
|
// 返回当前用户的记住登录状态
|
bool UserManager::isRememberMe() const {
|
return m_isRememberMe;
|
}
|
|
// 创建新用户,仅超级管理员有权限
|
bool UserManager::createUser(const std::string& username, const std::string& password, UserRole role,
|
std::chrono::minutes timeout, std::chrono::hours expiration) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can create new users." << std::endl;
|
return false;
|
}
|
|
std::string query = "INSERT INTO users (username, password, role, session_timeout, session_expiration) VALUES ('" +
|
username + "', '" + simpleEncryptDecrypt(password, "BandKey") + "', " + std::to_string(static_cast<int>(role)) + ", " +
|
std::to_string(timeout.count()) + ", " + std::to_string(expiration.count()) + ")";
|
return m_pDB->executeQuery(query);
|
}
|
|
// 删除用户,仅超级管理员有权限,且不能删除自己
|
bool UserManager::deleteUser(const std::string& username) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can delete users." << std::endl;
|
return false;
|
}
|
if (username == m_strCurrentUser) {
|
std::cerr << "SuperAdmin cannot delete their own account." << std::endl;
|
return false;
|
}
|
|
std::string query = "DELETE FROM users WHERE username = '" + username + "'";
|
return m_pDB->executeQuery(query);
|
}
|
|
// 获取所有用户信息,仅超级管理员有权限
|
std::vector<std::vector<std::string>> UserManager::getUsers() {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can retrieve user data." << std::endl;
|
return {};
|
}
|
|
// 查询整个用户表
|
std::string query = "SELECT username, password, role, session_timeout, session_expiration, last_login FROM users";
|
std::vector<std::vector<std::string>> results = m_pDB->fetchResults(query);
|
for (auto& row : results) {
|
row[1] = simpleEncryptDecrypt(row[1], "BandKey");
|
}
|
|
return results;
|
}
|
|
// 设置整个用户表的数据,仅超级管理员有权限
|
bool UserManager::setUsers(const std::vector<std::vector<std::string>>& usersData) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can set user data." << std::endl;
|
return false;
|
}
|
|
// 清空用户表
|
std::string deleteQuery = "DELETE FROM users";
|
if (!m_pDB->executeQuery(deleteQuery)) {
|
std::cerr << "Failed to clear the users table." << std::endl;
|
return false;
|
}
|
|
// 插入新的用户数据
|
for (const auto& user : usersData) {
|
if (user.size() != 6) {
|
std::cerr << "Invalid data format for user. Each user must have 6 fields." << std::endl;
|
return false;
|
}
|
|
std::string insertQuery = "INSERT INTO users (username, password, role, session_timeout, session_expiration, last_login) VALUES ('" +
|
user[0] + "', '" + simpleEncryptDecrypt(user[1], "BandKey") + "', " + user[2] + ", " + user[3] + ", " + user[4] + ", '" + user[5] + "')";
|
|
if (!m_pDB->executeQuery(insertQuery)) {
|
std::cerr << "Failed to insert user: " << user[0] << std::endl;
|
return false;
|
}
|
}
|
|
return true;
|
}
|
|
// 修改用户名,仅超级管理员有权限
|
bool UserManager::changeUsername(const std::string& username, const std::string& newUsername) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can change usernames." << std::endl;
|
return false;
|
}
|
|
std::string query = "UPDATE users SET username = '" + newUsername + "' WHERE username = '" + username + "'";
|
bool success = m_pDB->executeQuery(query);
|
|
// 如果是当前登录用户修改自己的用户名,更新成员变量并保存会话文件
|
if (success && m_strCurrentUser == username) {
|
m_strCurrentUser = newUsername;
|
|
// 如果“记住密码”已启用,更新会话文件
|
if (m_isRememberMe) {
|
saveSession();
|
}
|
}
|
return success;
|
}
|
|
// 修改用户密码(仅允许当前用户或超级管理员)
|
bool UserManager::changePassword(const std::string& username, const std::string& newPassword) {
|
if (username != m_strCurrentUser && m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Permission denied: Only the user or SuperAdmin can change passwords." << std::endl;
|
return false;
|
}
|
|
std::string query = "UPDATE users SET password = '" + simpleEncryptDecrypt(newPassword, "BandKey") +
|
"' WHERE username = '" + username + "'";
|
bool success = m_pDB->executeQuery(query);
|
|
// 如果是当前用户修改自己的密码,退出登录并清除会话文件
|
if (success && m_strCurrentUser == username) {
|
logout();
|
std::cout << "Password changed successfully. Please log in again." << std::endl;
|
}
|
|
return success;
|
}
|
|
// 更改用户角色,仅超级管理员有权限
|
bool UserManager::changeUserRole(const std::string& username, UserRole newRole) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can change user roles." << std::endl;
|
return false;
|
}
|
|
// 防止管理员更改自己的角色
|
if (m_strCurrentUser == username) {
|
std::cerr << "SuperAdmin cannot change their own role." << std::endl;
|
return false;
|
}
|
|
std::string query = "UPDATE users SET role = " + std::to_string(static_cast<int>(newRole)) +
|
" WHERE username = '" + username + "'";
|
return m_pDB->executeQuery(query);
|
}
|
|
// 修改用户的 session_timeout,仅超级管理员有权限
|
bool UserManager::changeUserSessionTimeout(const std::string& username, int newTimeoutMinutes) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can change session timeout." << std::endl;
|
return false;
|
}
|
|
std::string query = "UPDATE users SET session_timeout = " + std::to_string(newTimeoutMinutes) +
|
" WHERE username = '" + username + "'";
|
bool success = m_pDB->executeQuery(query);
|
// 如果是当前登录用户修改自己的超时设置,更新成员变量
|
if (success && m_strCurrentUser == username) {
|
m_tmSessionTimeout = std::chrono::minutes(newTimeoutMinutes);
|
|
if (m_isRememberMe) {
|
saveSession();
|
}
|
}
|
return success;
|
}
|
|
// 修改用户的 session_expiration,仅超级管理员有权限
|
bool UserManager::changeUserSessionExpiration(const std::string& username, int newExpirationHours) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can change session expiration." << std::endl;
|
return false;
|
}
|
|
std::string query = "UPDATE users SET session_expiration = " + std::to_string(newExpirationHours) +
|
" WHERE username = '" + username + "'";
|
bool success = m_pDB->executeQuery(query);
|
// 如果是当前登录用户修改自己的过期设置,更新成员变量
|
if (success && m_strCurrentUser == username) {
|
m_tmSessionExpiration = std::chrono::hours(newExpirationHours);
|
|
if (m_isRememberMe) {
|
saveSession();
|
}
|
}
|
return success;
|
}
|
|
// 获取所有用户名称
|
std::vector<std::string> UserManager::getUsernames() {
|
std::vector<std::string> usernames;
|
std::string query = "SELECT username FROM users";
|
auto results = m_pDB->fetchResults(query);
|
|
for (const auto& row : results) {
|
if (!row.empty()) {
|
usernames.push_back(row[0]); // 获取用户名列的值
|
}
|
}
|
|
return usernames;
|
}
|
|
// 获取指定用户名的用户信息
|
std::vector<std::string> UserManager::getUserInfo(const std::string& username)
|
{
|
// 构建查询语句
|
std::ostringstream query;
|
query << "SELECT username, password, role, session_timeout, session_expiration, last_login "
|
<< "FROM users WHERE username = '" << username << "'";
|
|
// 执行查询并获取结果
|
auto results = m_pDB->fetchResults(query.str());
|
if (results.empty()) {
|
return {};
|
}
|
|
// 返回查询到的第一行数据
|
return results[0];
|
}
|
|
// 更新最后活动时间,用于无操作超时检测
|
void UserManager::updateActivityTime() {
|
m_tpLastActivity = std::chrono::system_clock::now();
|
std::cout << "Activity updated at: " << std::chrono::system_clock::to_time_t(m_tpLastActivity) << std::endl;
|
}
|
|
// 设置无操作超时时间
|
void UserManager::setSessionTimeout(std::chrono::minutes timeout) {
|
m_tmSessionTimeout = timeout;
|
}
|
|
// 检查是否超过无操作超时时间
|
bool UserManager::isInactiveTimeout() const {
|
auto now = std::chrono::system_clock::now();
|
auto elapsedSeconds = std::chrono::duration_cast<std::chrono::seconds>(now - m_tpLastActivity).count();
|
return elapsedSeconds > m_tmSessionTimeout.count() * 60;
|
}
|
|
// 初始化无操作检测,包括设置全局鼠标和键盘钩子
|
void UserManager::initializeIdleDetection(HWND hwnd) {
|
updateActivityTime();
|
m_hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, (HINSTANCE) nullptr, 0);
|
m_hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, (HINSTANCE) nullptr, 0);
|
::SetTimer(hwnd, 1, 60000, nullptr);
|
}
|
|
// 终止无操作检测,清除鼠标和键盘钩子
|
void UserManager::terminateIdleDetection() {
|
if (m_hMouseHook) {
|
UnhookWindowsHookEx(m_hMouseHook);
|
m_hMouseHook = nullptr;
|
}
|
if (m_hKeyboardHook) {
|
UnhookWindowsHookEx(m_hKeyboardHook);
|
m_hKeyboardHook = nullptr;
|
}
|
::KillTimer(nullptr, 1);
|
}
|
|
// 获取当前登录用户名
|
std::string UserManager::getCurrentUser() const {
|
return m_strCurrentUser;
|
}
|
|
// 修改当前登录用户名
|
void UserManager::setCurrentUser(const std::string& strName) {
|
m_strCurrentUser = strName;
|
}
|
|
// 获取当前登录用户密码
|
std::string UserManager::getCurrentPass() const {
|
return m_strCurrentPass;
|
}
|
|
// 修改当前登录用户密码
|
void UserManager::setCurrentPass(const std::string& strPass) {
|
m_strCurrentPass = strPass;
|
}
|
|
// 获取当前登录用户角色
|
UserRole UserManager::getCurrentUserRole() const {
|
return m_enCurrentUserRole;
|
}
|
|
// 修改当前登录用户角色
|
void UserManager::setCurrentUserRole(UserRole emRole) {
|
m_enCurrentUserRole = emRole;
|
}
|
|
// 获取当前登录用户的无操作超时时间
|
std::chrono::minutes UserManager::getSessionTimeout() const {
|
return m_tmSessionTimeout;
|
}
|
|
// 获取当前登录用户的会话过期时间
|
std::chrono::hours UserManager::getSessionExpiration() const {
|
return m_tmSessionExpiration;
|
}
|
|
// 全局鼠标钩子回调,记录活动时间
|
LRESULT CALLBACK UserManager::LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
|
if (nCode == HC_ACTION) {
|
UserManager::getInstance().updateActivityTime();
|
std::cout << "Mouse event detected. Activity time updated." << std::endl;
|
}
|
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
}
|
|
// 全局键盘钩子回调,记录活动时间
|
LRESULT CALLBACK UserManager::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
|
if (nCode == HC_ACTION) {
|
UserManager::getInstance().updateActivityTime();
|
std::cout << "Keyboard event detected. Activity time updated." << std::endl;
|
}
|
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
}
|