aa8af6c2e0
Flask + SQLite + Bootstrap5 暗色主题 - 仪表盘: 在线/离线统计 + 最近代理 + 操作日志 - 代理 CRUD: 增删改 + 启用/禁用 + 单/批量健康检测(SOCKS5) - 分组管理: 创建/删除/筛选 - 操作日志: 分页查询 - RESTful API + Web 界面 - 管理员登录认证 (SM_ADMIN_PASSWORD 环境变量)
62 lines
2.3 KiB
Python
62 lines
2.3 KiB
Python
from flask import Blueprint, request, session, redirect, url_for, abort, current_app
|
|
from functools import wraps
|
|
|
|
bp = Blueprint("auth", __name__)
|
|
|
|
|
|
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("main.dashboard"))
|
|
|
|
if request.method == "POST":
|
|
import os
|
|
user = request.form.get("username", "")
|
|
pwd = request.form.get("password", "")
|
|
valid_user = os.environ.get("SM_ADMIN_USER", "admin")
|
|
valid_pwd = os.environ.get("SM_ADMIN_PASSWORD", "")
|
|
if user == valid_user and pwd == valid_pwd:
|
|
session["logged_in"] = True
|
|
session.permanent = True
|
|
return redirect(request.args.get("next") or url_for("main.dashboard"))
|
|
return f"<script>alert('用户名或密码错误');history.back();</script>", 401
|
|
|
|
return """
|
|
<!doctype html>
|
|
<html><head><meta charset="utf-8">
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<title>登录 · SOCKS Manager</title></head>
|
|
<body class="bg-dark d-flex align-items-center justify-content-center" style="min-height:100vh">
|
|
<div class="card shadow" style="width:360px">
|
|
<div class="card-body p-4">
|
|
<h4 class="text-center mb-4">SOCKS Manager</h4>
|
|
<p class="text-muted text-center small mb-4">SOCKS5 代理管理系统</p>
|
|
<form method="post">
|
|
<div class="mb-3"><label class="form-label">用户名</label>
|
|
<input name="username" class="form-control" autofocus required></div>
|
|
<div class="mb-3"><label class="form-label">密码</label>
|
|
<input name="password" type="password" class="form-control" required></div>
|
|
<button type="submit" class="btn btn-primary w-100">登录</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</body></html>
|
|
"""
|
|
|
|
|
|
@bp.route("/logout")
|
|
def logout():
|
|
session.clear()
|
|
return redirect(url_for("auth.login"))
|