558bd8153f
架构: - engine/server.py: asyncio SOCKS5 服务器引擎(含隧道/认证/限速) - engine/instances.py: 多实例管理器(独立事件循环/热启动/热停止) - services/user_service.py: 用户认证/流量统计/IP白名单/防爆破 - services/stats_service.py: 实时监控/流量趋势/连接追踪 - services/backup_service.py: 数据库备份与恢复 - api/v1.py: 完整 RESTful API - web/routes.py: Web 管理面板(暗色 Bootstrap 5 主题) 功能覆盖: ✅ 多实例 SOCKS5 管理(创建/启动/停止/重启/热加载) ✅ 用户认证(无认证/账号密码/流量上限/限速/并发限制) ✅ IP 白名单/黑名单/防爆破 ✅ 实时仪表盘(CPU/内存/网络/活跃连接) ✅ 流量统计(30天趋势图/用户排名/实例统计) ✅ 活跃连接追踪 ✅ 审计日志(事件/用户/IP 筛选) ✅ 数据库备份与恢复 ✅ 管理员密码保护 ✅ 16 项功能测试全部通过
76 lines
2.9 KiB
Python
76 lines
2.9 KiB
Python
"""登录认证。"""
|
|
import os
|
|
from functools import wraps
|
|
from flask import Blueprint, request, session, redirect, url_for
|
|
|
|
bp = Blueprint("auth", __name__)
|
|
|
|
|
|
def _get_admin_creds():
|
|
return (
|
|
os.environ.get("SM_ADMIN_USER", "admin"),
|
|
os.environ.get("SM_ADMIN_PASSWORD", ""),
|
|
)
|
|
|
|
|
|
def login_required(f):
|
|
@wraps(f)
|
|
def decorated(*args, **kwargs):
|
|
if not session.get("logged_in"):
|
|
if request.path.startswith("/api/"):
|
|
return {"error": "unauthorized"}, 401
|
|
return redirect(url_for("auth.login", next=request.url))
|
|
return f(*args, **kwargs)
|
|
return decorated
|
|
|
|
|
|
@bp.route("/login", methods=["GET", "POST"])
|
|
def login():
|
|
if session.get("logged_in"):
|
|
return redirect(url_for("web.index"))
|
|
if request.method == "POST":
|
|
u, p = _get_admin_creds()
|
|
form_user = request.form.get("username", "")
|
|
form_pwd = request.form.get("password", "")
|
|
if form_user == u and form_pwd == p:
|
|
session["logged_in"] = True
|
|
session.permanent = True
|
|
return redirect(request.args.get("next") or url_for("web.index"))
|
|
return {"error": "用户名或密码错误"}, 401
|
|
return _render_login()
|
|
|
|
|
|
@bp.route("/logout")
|
|
def logout():
|
|
session.clear()
|
|
return redirect(url_for("auth.login"))
|
|
|
|
|
|
def _render_login():
|
|
return """<!doctype html>
|
|
<html lang="zh-CN"><head><meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>登录 · SOCKS Manager</title>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<style>
|
|
body{background:#0b0e14;color:#e2e8f0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}
|
|
.card{background:#161922;border:1px solid #1f2335;border-radius:.75rem}
|
|
.form-control{background:#0b0e14;border:1px solid #1f2335;color:#e2e8f0;border-radius:.5rem}
|
|
.form-control:focus{border-color:#818cf8;box-shadow:0 0 0 3px rgba(129,140,248,.15);background:#0b0e14;color:#e2e8f0}
|
|
.btn-primary{background:#818cf8;border-color:#818cf8;border-radius:.5rem}
|
|
.btn-primary:hover{background:#6366f1;border-color:#6366f1}
|
|
h4{color:#818cf8;font-weight:700}
|
|
</style></head>
|
|
<body class="d-flex align-items-center justify-content-center" style="min-height:100vh">
|
|
<div class="card shadow-lg p-5" style="width:380px">
|
|
<h4 class="text-center mb-2">SOCKS Manager</h4>
|
|
<p class="text-center text-muted small mb-4">SOCKS5 代理管理平台</p>
|
|
<form method="post">
|
|
<div class="mb-3"><label class="form-label text-muted small">用户名</label>
|
|
<input name="username" class="form-control" value="admin" autofocus required></div>
|
|
<div class="mb-4"><label class="form-label text-muted small">密码</label>
|
|
<input name="password" type="password" class="form-control" required></div>
|
|
<button type="submit" class="btn btn-primary w-100">登 录</button>
|
|
</form>
|
|
</div></body></html>"""
|