feat: 添加登录认证,防止未授权访问

- 访问任何页面需先输入密码登录
- session有效期7天,无需频繁登录
- 密码通过环境变量ADMIN_PASSWORD配置,默认admin123
- 导航栏添加退出按钮
- 放行/login和/static及socket.io路径
This commit is contained in:
2026-04-02 10:46:46 +08:00
parent 400569ad03
commit 6ab6666cac
5 changed files with 92 additions and 2 deletions

View File

@@ -1,15 +1,19 @@
import os
import sys
import hashlib
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from flask import Flask, redirect, url_for
from flask import Flask, redirect, url_for, request, session, render_template
from flask_socketio import SocketIO
from server.database import init_db
from server.routers import accounts, tasks, orders
socketio = SocketIO(cors_allowed_origins="*")
# 访问密码,可通过环境变量 ADMIN_PASSWORD 设置,默认 admin123
ADMIN_PASSWORD = os.environ.get('ADMIN_PASSWORD', 'admin123')
def create_app():
app = Flask(
@@ -17,10 +21,41 @@ def create_app():
template_folder=os.path.join(os.path.dirname(__file__), '..', 'templates'),
static_folder=os.path.join(os.path.dirname(__file__), '..', 'static'),
)
app.secret_key = 'snatcher-secret-key-change-me'
app.secret_key = os.environ.get(
'SECRET_KEY', 'snatcher-secret-key-change-me')
init_db()
# ── 登录认证 ──
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
pwd = request.form.get('password', '')
if pwd == ADMIN_PASSWORD:
session['authenticated'] = _hash(pwd)
session.permanent = True
app.permanent_session_lifetime = __import__(
'datetime').timedelta(days=7)
return redirect(request.args.get('next', '/'))
return render_template('login.html', error='密码错误')
return render_template('login.html')
@app.route('/logout')
def logout():
session.clear()
return redirect('/login')
@app.before_request
def require_auth():
# 放行登录页和静态资源
if request.path in ('/login',) or request.path.startswith('/static'):
return
# 放行 SocketIO 的内部路径
if request.path.startswith('/socket.io'):
return
if session.get('authenticated') != _hash(ADMIN_PASSWORD):
return redirect(url_for('login', next=request.path))
app.register_blueprint(accounts.bp)
app.register_blueprint(tasks.bp)
app.register_blueprint(orders.bp)
@@ -35,6 +70,10 @@ def create_app():
return app
def _hash(s):
return hashlib.sha256(s.encode()).hexdigest()[:16]
def _register_socketio_events():
import asyncio
from server.services.remote_browser import get_session