更改验证

This commit is contained in:
MasonLiu 2026-08-25 00:07:26 +08:00
parent 00617621f9
commit 9e85e64345
6 changed files with 260 additions and 85 deletions

View File

@ -110,16 +110,19 @@
## 💻 技术栈
### 后端
- **PHP 7.4+**Web服务器端逻辑
- **Python 3.6+**:后台监控服务
- **SQLite 3**:轻量级数据库
### 前端
- **HTML5/CSS3**:页面结构和样式
- **JavaScript**:交互逻辑
- **响应式设计**:支持移动端访问
### 依赖库
- **PHP**: cURL, PDO-SQLite
- **Python**: requests, schedule, sqlite3
@ -164,13 +167,15 @@ chmod 755 app/install.sh
首次访问会自动跳转到配置页面添加第一个VPS平台配置。
设置访问密码后,进入 `index.php``config_add.php` 时需先输入访问密码POST 方式验证),验证成功后建立 PHP 会话(有效期 30 分钟,操作自动续期)。
---
## ⚙️ 配置说明
### 添加VPS平台配置
1. 访问 `config_add.php?pass=YOUR_API_PASS`
1. 访问 `config_add.php`,首次访问需先设置访问密码
2. 填写配置信息:
- **API标识**:自定义名称(唯一)
- **网站类型**:选择平台(目前支持魔方平台)
@ -184,6 +189,7 @@ chmod 755 app/install.sh
### 配置示例
**魔方平台配置**
```
API标识: 核云IDC
网站类型: 魔方平台
@ -196,6 +202,7 @@ API密钥: your_api_key
![API_KEY](./src/api.png)
⚠️ **重要提示**
- 网站链接只填写根域名,不要包含 `/v1``/api` 等路径
- API标识必须唯一不能重复
- 确保账户和密码正确
@ -208,14 +215,18 @@ API密钥: your_api_key
#### 查看VPS列表
访问 `index.php?pass=YOUR_API_PASS`,可以看到:
访问 `index.php`,输入访问密码登录后即可看到:
- 按配置分组的VPS列表
- 每个VPS的状态、IP、配置信息
- 实时统计数据
> 登录会话有效期 30 分钟(滑动过期),每次请求新数据会自动续期;超过 30 分钟无操作需重新登录。
#### 操作VPS
每个VPS卡片提供三个操作按钮
- **⚡ 开机**启动VPS
- **🔴 关机**关闭VPS
- **🔄 硬重启**强制重启VPS
@ -225,6 +236,7 @@ API密钥: your_api_key
#### 刷新VPS列表
点击顶部工具栏的 "🔄 手动刷新VPS列表" 按钮:
1. 从API获取最新的VPS列表
2. 更新数据库中的VPS信息
3. 获取每个VPS的详细配置CPU、内存、磁盘、带宽、系统
@ -243,7 +255,6 @@ sudo systemctl start idc_monitor
sudo systemctl status idc_monitor
```
#### 停止监控
```bash
@ -284,11 +295,11 @@ sudo systemctl restart idc_monitor
### 数据库文件
| 文件名 | 用途 | 主要表 |
|--------|------|--------|
| `vps.db` | 存储平台配置 | `configs` |
| `vpslist.db` | 存储VPS列表 | `vps_list` |
| `status.db` | 存储监控记录 | `ping_status`, `vps_summary` |
| 文件名 | 用途 | 主要表 |
| ------------ | ------------ | ---------------------------- |
| `vps.db` | 存储平台配置 | `configs` |
| `vpslist.db` | 存储VPS列表 | `vps_list` |
| `status.db` | 存储监控记录 | `ping_status`, `vps_summary` |
### 表结构
@ -421,7 +432,8 @@ WantedBy=multi-user.target
### 访问控制
- **API密码保护**:所有页面都需要通过 `?pass=API_PASS` 验证
- **会话密码保护**所有页面通过前端输入访问密码POST 方式)验证,验证成功后建立 PHP 会话
- **会话有效期**:单次会话 30 分钟,用户请求新数据后自动刷新会话有效期(滑动过期)
- **密码文件**:存储在 `app/pass.php`,权限设置为 600
- **数据库保护**Nginx配置禁止直接访问 `.db` 文件或者限制访问app路径需要basic认证
@ -445,7 +457,8 @@ WantedBy=multi-user.target
### Q1: 页面显示"0台VPS"怎么办?
**A**:
**A**:
1. 点击"手动刷新VPS列表"按钮
2. 检查配置是否正确特别是site_url不要包含路径
3. 查看PHP错误日志`tail -f /var/log/php/error.log`
@ -455,6 +468,7 @@ WantedBy=multi-user.target
### Q2: 监控服务无法启动?
**A**:
```bash
# 检查服务状态
sudo systemctl status idc_monitor
@ -472,8 +486,9 @@ journalctl -u idc_monitor -n 50
### Q3: exec函数被禁用怎么办
**A**:
**A**:
系统已经做了兼容处理:
- 如果exec被禁用会显示友好提示
- 需要手动执行安装脚本:`sudo bash app/install.sh`
- 监控服务仍然可以正常运行
@ -484,11 +499,13 @@ journalctl -u idc_monitor -n 50
**A**:
可能原因:
1. 数据库中还没有该VPS的记录
2. 多次调用导致状态被覆盖(已修复)
3. API返回异常
解决方法:
- 手动刷新VPS列表
- 检查日志确认API调用是否正常
- 等待下一次监控循环
@ -498,18 +515,20 @@ journalctl -u idc_monitor -n 50
### Q5: 如何添加新的VPS平台
**A**:
1. 在 `app/monitor.py` 中创建新的适配器类
2. 继承 `PlatformAdapter` 基类
3. 实现必要的方法login, get_vps_list, get_vps_status等
4. 在 `load_configs_and_create_adapters()` 中添加判断逻辑
示例:
```python
class AliyunAdapter(PlatformAdapter):
def login(self):
# 实现阿里云登录逻辑
pass
def get_vps_list(self):
# 实现获取VPS列表逻辑
pass
@ -520,11 +539,13 @@ class AliyunAdapter(PlatformAdapter):
### Q6: 数据库文件在哪里?
**A**:
- `app/db/vps.db` - 配置数据库
- `app/db/vpslist.db` - VPS列表数据库
- `app/db/status.db` - 监控状态数据库
可以使用SQLite工具查看
```bash
sqlite3 app/db/vpslist.db
.tables
@ -536,6 +557,7 @@ SELECT * FROM vps_list;
### Q7: 如何备份数据?
**A**:
```bash
# 备份所有数据库
cp app/db/*.db backup/$(date +%Y%m%d)/
@ -552,7 +574,6 @@ sqlite3 app/db/vpslist.db ".dump" > backup/vpslist.sql
---
## 📧 联系方式
- **项目地址**: [https://git.masonliu.com/MasonLiu/VPSHUB](https://git.masonliu.com/MasonLiu/VPSHUB)
@ -564,6 +585,7 @@ sqlite3 app/db/vpslist.db ".dump" > backup/vpslist.sql
## 🙏 致谢
感谢以下开源项目:
- [PHP](https://www.php.net/)
- [Python](https://www.python.org/)
- [SQLite](https://www.sqlite.org/)

175
app/auth.php Normal file
View File

@ -0,0 +1,175 @@
<?php
/**
* VPS Hub 统一会话认证模块
*
* 功能:
* - 前端输入访问密码POST验证后建立 PHP 会话
* - 单次会话有效期 30 分钟(滑动过期)
* - 用户每次发起有效请求后自动刷新会话有效期
*
* 用法:
* require_once __DIR__ . '/app/auth.php';
* requireAuth(); // 未登录则展示登录页并终止脚本
* isLoggedIn(); // 返回当前会话是否有效
* attemptLogin($password); // 验证密码并建立会话
* logout(); // 手动退出登录
*/
// 会话有效期30 分钟(秒)
if (!defined('SESSION_LIFETIME')) {
define('SESSION_LIFETIME', 1800);
}
// 会话垃圾回收最大存活时间(需在 session_start 之前设置)
ini_set('session.gc_maxlifetime', SESSION_LIFETIME);
// 启动会话
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
/**
* 判断当前会话是否已通过认证
* 已登录且未超过 30 分钟无操作时,刷新会话有效期(滑动过期)
*
* @return bool 是否有效登录态
*/
function isLoggedIn() {
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
return false;
}
// 滑动过期判断:超过 30 分钟无任何请求则会话失效
if (!isset($_SESSION['last_activity']) || (time() - intval($_SESSION['last_activity'])) > SESSION_LIFETIME) {
// 销毁过期会话
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
}
if (session_status() === PHP_SESSION_ACTIVE) {
session_destroy();
}
return false;
}
// 用户请求了新数据,刷新会话有效期
$_SESSION['last_activity'] = time();
return true;
}
/**
* 验证访问密码并建立登录会话
* 使用 hash_equals 进行时序安全比对,防止时序攻击
*
* @param string $password 用户提交的访问密码
* @return bool 是否登录成功
*/
function attemptLogin($password) {
if (!defined('API_PASS')) {
return false;
}
if (hash_equals(API_PASS, (string)$password)) {
// 会话固定攻击防护重新生成会话ID
session_regenerate_id(true);
$_SESSION['admin_logged_in'] = true;
$_SESSION['last_activity'] = time();
return true;
}
return false;
}
/**
* 强制要求登录认证
* 未认证时输出登录页面并终止当前脚本
* 已认证时直接返回,不影响后续流程
*
* @param string $redirect 登录成功后跳转的站内地址(可选,默认回到当前页面)
*/
function requireAuth($redirect = '') {
if (isLoggedIn()) {
return;
}
// 处理登录表单提交POST 携带 auth_password
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['auth_password'])) {
if (attemptLogin($_POST['auth_password'])) {
// 登录成功,跳转回目标页面
$target = !empty($_POST['redirect']) ? trim($_POST['redirect']) : $redirect;
// 仅允许站内跳转,防止开放重定向
if ($target && strpos($target, '://') === false && strpos($target, '\\') === false) {
header('Location: ' . $target);
} else {
header('Location: ' . $_SERVER['PHP_SELF']);
}
exit;
}
$error = '访问密码错误,请重试!';
}
// 构造登录成功后返回的地址(默认当前请求地址)
$currentPage = $_SERVER['PHP_SELF'];
$queryString = $_SERVER['QUERY_STRING'] ?? '';
$redirectTarget = !empty($redirect)
? $redirect
: ($queryString ? $currentPage . '?' . $queryString : $currentPage);
// 输出登录页面
header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="./static/favicon.ico" type="image/x-icon">
<link href="./static/initial.css" rel="stylesheet" type="text/css">
<title>访问验证 - VPS Hub</title>
</head>
<body>
<div class="config-container">
<div class="config-header">
<h1>🔐 VPS Hub</h1>
<p>请输入访问密码以进入管理面板</p>
</div>
<?php if ($error): ?>
<div class="error-message"> <?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<form method="POST" action="<?php echo htmlspecialchars($currentPage); ?>">
<input type="hidden" name="redirect" value="<?php echo htmlspecialchars($redirectTarget); ?>">
<div class="form-group">
<label for="auth_password">访问密码</label>
<input type="password" id="auth_password" name="auth_password" required
placeholder="请输入访问密码" autofocus autocomplete="current-password">
</div>
<button type="submit" class="btn-submit">🔓 登录</button>
</form>
<div class="info-box" style="margin-top: 20px;">
💡 登录会话有效期 30 分钟,期间操作会自动续期;超过 30 分钟无操作需重新登录。
</div>
</div>
</body>
</html>
<?php
exit;
}
/**
* 退出登录并销毁会话
*/
function logout() {
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
}
if (session_status() === PHP_SESSION_ACTIVE) {
session_destroy();
}
}

View File

@ -5,6 +5,7 @@
*/
require_once __DIR__ . '/app/db_helper.php';
require_once __DIR__ . '/app/auth.php';
require_once __DIR__ . '/mofangidc.php';
// Token文件路径(存储API_PASS)
@ -33,7 +34,10 @@ if ($needSetup && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['setup_p
if (file_put_contents($tokenFile, $content)) {
chmod($tokenFile, 0600);
header('Location: config_add.php?pass=' . urlencode($apiPass));
// 密码刚由本人设置,直接建立登录会话并跳转
include $tokenFile;
attemptLogin($apiPass);
header('Location: config_add.php');
exit;
} else {
$setupError = '保存失败,请检查目录权限!';
@ -114,14 +118,8 @@ if (file_exists($tokenFile)) {
include $tokenFile;
}
// 验证pass参数
$pass = isset($_GET['pass']) ? $_GET['pass'] : '';
if (!defined('API_PASS') || $pass !== API_PASS) {
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['status' => 403, 'msg' => '访问密码错误'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
exit;
}
// 会话认证前端输入密码验证后建立会话30分钟滑动过期
requireAuth();
// 处理添加配置
$message = '';
@ -383,7 +381,10 @@ $configs = $db->query('SELECT * FROM configs ORDER BY id');
<div class="header">
<h1>⚙️ VPS配置管理</h1>
<p>添加和管理多平台VPS配置</p>
<a href="index.php?pass=<?php echo urlencode($pass); ?>" class="btn" style="float: right; margin-top: -60px;">返回首页</a>
<div style="float: right; margin-top: -60px; display: flex; gap: 10px; align-items: center;">
<a href="index.php" class="btn">返回首页</a>
<a href="index.php?logout=1" class="btn" style="background: #6c757d; color: white;" onclick="return confirm('确认退出登录?')">🚪 退出登录</a>
</div>
</div>
<div class="content">

View File

@ -1,6 +1,7 @@
<?php
require_once __DIR__ . '/app/db_helper.php';
require_once __DIR__ . '/app/logger.php';
require_once __DIR__ . '/app/auth.php';
require_once __DIR__ . '/mofangidc.php';
require_once __DIR__ . '/tencentcloud.php';
require_once __DIR__ . '/aliyun.php';
@ -17,15 +18,16 @@ if (!file_exists($tokenFile)) {
// 加载API_PASS
include $tokenFile;
// 验证pass参数
$pass = isset($_GET['pass']) ? $_GET['pass'] : '';
if (!defined('API_PASS') || $pass !== API_PASS) {
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['status' => 403, 'msg' => '访问密码错误或者未输入密码,请拼接?pass=API_PASS后再尝试访问'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
// 处理退出登录(需在会话认证之前,保证已登录用户也能退出)
if (isset($_GET['logout'])) {
logout();
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
// 会话认证前端输入密码验证后建立会话30分钟滑动过期
requireAuth();
// 处理操作请求
$message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
@ -295,6 +297,15 @@ foreach ($vpsList as $vps) {
.btn-refresh:hover {
background-color: #0056b3;
}
.btn-logout {
background-color: #6c757d;
color: white;
text-decoration: none;
}
.btn-logout:hover {
background-color: #5a6268;
color: white;
}
.config-title {
display: flex;
justify-content: space-between;
@ -478,9 +489,14 @@ foreach ($vpsList as $vps) {
</button>
</form>
<a href="config_add.php?pass=<?php echo urlencode($pass); ?>" class="btn btn-success">
添加配置源
</a>
<div style="display: flex; gap: 10px; align-items: center;">
<a href="config_add.php" class="btn btn-success">
添加配置源
</a>
<a href="index.php?logout=1" class="btn btn-logout" onclick="return confirm('确认退出登录?')">
🚪 退出登录
</a>
</div>
</div>
<!-- 统计信息 -->
@ -500,7 +516,7 @@ foreach ($vpsList as $vps) {
<div class="empty-state">
<h3>📭 暂无配置</h3>
<p>请先添加VPS配置才能开始管理</p>
<a href="config_add.php?pass=<?php echo urlencode($pass); ?>" class="btn btn-success" style="margin-top: 20px;">
<a href="config_add.php" class="btn btn-success" style="margin-top: 20px;">
添加第一个配置
</a>
</div>

View File

@ -1,54 +1,16 @@
<?php
require_once __DIR__ . '/app/logger.php';
require_once __DIR__ . '/app/pass.php';
require_once __DIR__ . '/app/auth.php';
// 检查是否已登录(简单验证)
session_start();
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
// 如果没有登录,显示简单的密码验证
if (isset($_POST['password'])) {
// 使用pass.php中定义的API_PASS作为密码
if ($_POST['password'] === API_PASS) {
$_SESSION['admin_logged_in'] = true;
} else {
$error = '密码错误';
}
}
if (!isset($_SESSION['admin_logged_in'])) {
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>VPSHUB - 日志查看</title>
<style>
body { font-family: Arial, sans-serif; margin: 50px; background: #f5f5f5; }
.login-box { max-width: 400px; margin: 100px auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
h2 { margin-top: 0; color: #333; }
input[type="password"] { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; }
button { width: 100%; padding: 10px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
button:hover { background: #0056b3; }
.error { color: red; margin-bottom: 10px; }
</style>
</head>
<body>
<div class="login-box">
<h2>🔐 日志查看权限验证</h2>
<?php if (isset($error)): ?>
<div class="error"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<form method="POST">
<input type="password" name="password" placeholder="请输入管理员密码" required>
<button type="submit">登录</button>
</form>
</div>
</body>
</html>
<?php
exit;
}
// 加载API_PASS未设置则跳转到配置页
if (!file_exists(__DIR__ . '/app/pass.php')) {
header('Location: config_add.php');
exit;
}
include __DIR__ . '/app/pass.php';
// 统一会话认证前端输入密码验证后建立会话30分钟滑动过期
requireAuth();
// 处理操作
$action = $_GET['action'] ?? '';

View File

@ -6,7 +6,7 @@
初次访问该php页面时用户需设置网页自定义访问密码API_PASS运行输入大小写字母以及数字最低8位数
存在API_PASS时需跟参数?pass=API_PASS才允许访问
存在API_PASS时访问需先在前端输入访问密码POST方式验证验证成功后建立PHP会话会话有效期30分钟滑动过期用户请求新数据后自动续期
用户点击添加配置按钮,新列出一列,分别是:
旧数据也会读取并展示
@ -18,14 +18,14 @@
3. 进行ping访问测试后将结果记录于./app/db/中的status.db中保留最近三十天数据
记录项目标IP地址或域名状态正常或异常延时单位ms 毫秒)
每天0点时总结前一天中各VPS的ping响应数据记录在该数据库中的新表 vps_summary 中。该表需包含以下字段VPS标识vps_id、统计日期date、平均延迟avg_latency_ms、最大延迟max_latency_ms、最小延迟min_latency_ms。同时分级记录延迟分布情况延迟低于100ms的次数count_under_100、100ms~300ms的次数count_100_to_300、300ms~500ms的次数count_300_to_500以及延迟超过500ms或ping异常的丢包/超时次数count_abnormal。根据延迟表现计算高可用评分100ms以内权重最高300ms以内为良好500ms以内为可用超过500ms标记为低可用异常则标记为不可用。记录为新字段服务器可用性优秀/良好/一般/不可用)
记录项目标IP地址或域名状态正常或异常延时单位ms 毫秒)
每天0点时总结前一天中各VPS的ping响应数据记录在该数据库中的新表 vps_summary 中。该表需包含以下字段VPS标识vps_id、统计日期date、平均延迟avg_latency_ms、最大延迟max_latency_ms、最小延迟min_latency_ms。同时分级记录延迟分布情况延迟低于100ms的次数count_under_100、100ms~300ms的次数count_100_to_300、300ms~500ms的次数count_300_to_500以及延迟超过500ms或ping异常的丢包/超时次数count_abnormal。根据延迟表现计算高可用评分100ms以内权重最高300ms以内为良好500ms以内为可用超过500ms标记为低可用异常则标记为不可用。记录为新字段服务器可用性优秀/良好/一般/不可用)
4. 首次使用网页并添加数据后,调用./app/install.sh进行system服务注册
#### 首页 index.php
1. 查询是否存在API_PASS若存在则需跟参数?pass=API_PASS才能访问
1. 查询是否存在API_PASS若存在访问时需先输入访问密码POST方式验证建立PHP会话会话有效期30分钟滑动过期
2. 若不存在则跳转至config_add.php页
@ -66,4 +66,3 @@
获取到的认证token存储于./app/token.php中记录为两小时
3. 若section为True且ping测试失败调用API对该机器进行状态查询若返回状态为关机则尝试开机隔60秒后再进行状态查询并再次尝试开机60秒后查询还是为异常的话则记录异常进入下一个循环多台机器关机时依次进行状态查询和开机然后间隔60秒再进行操作不同的机器不需要间隔