feat: add email-based authentication

This commit is contained in:
2026-08-03 18:49:08 +08:00
parent 82a8b4187a
commit f2209a0e00
19 changed files with 641 additions and 1555 deletions
+18 -8
View File
@@ -2,14 +2,17 @@ from __future__ import annotations
import logging
from flask import Flask, abort, jsonify, request
from flask import Flask, abort, jsonify, request, redirect, session
from flask_login import current_user, logout_user
from .config import Config, DATA_DIR, ensure_dirs
from .extensions import db, login_manager
from .models import AppSetting, User
from .migrations import upgrade_schema
from .prediction import FEATURES, load_model
from .security import csrf_token, validate_csrf_token
from .time_utils import current_year_for_timezone, format_datetime_for_timezone
from .time_utils import utc_now
def create_app(config_object: type[Config] = Config, *, load_model_on_start: bool = True) -> Flask:
@@ -34,7 +37,7 @@ def create_app(config_object: type[Config] = Config, *, load_model_on_start: boo
app.register_blueprint(bp)
with app.app_context():
db.create_all()
upgrade_schema()
init_admin_user(app)
if load_model_on_start:
@@ -59,23 +62,26 @@ def configure_logging() -> None:
def init_admin_user(app: Flask) -> None:
admin_username = app.config["ADMIN_USERNAME"]
admin_password = app.config["ADMIN_PASSWORD"]
if admin_password:
admin_email = app.config["ADMIN_EMAIL"]
if admin_password and admin_email:
admin = User.query.filter_by(username=admin_username).first()
if admin is None:
admin = User(username=admin_username, is_admin=True)
admin = User(username=admin_username, email=admin_email, is_admin=True, is_active_account=True)
admin.set_password(admin_password)
db.session.add(admin)
else:
admin.is_admin = True
if not admin.check_password(admin_password):
admin.set_password(admin_password)
if not admin.email:
admin.email = admin_email
admin.email_verified_at = utc_now()
admin.is_active_account = True
db.session.commit()
elif not User.query.filter_by(is_admin=True).first():
logging.warning("未设置 ADMIN_PASSWORD,跳过自动创建管理员账号。")
logging.warning("未设置 ADMIN_PASSWORD 或 ADMIN_EMAIL,跳过自动创建管理员账号。")
default_admin = User.query.filter_by(username="admin", is_admin=True).first()
if default_admin and default_admin.check_password("admin123"):
logging.warning("检测到默认管理员密码 admin123,请立即通过 ADMIN_PASSWORD 更新。")
logging.warning("检测到默认管理员密码 admin123,请通过账户安全页立即更新。")
def register_app_hooks(app: Flask) -> None:
@@ -114,6 +120,10 @@ def register_app_hooks(app: Flask) -> None:
@app.before_request
def protect_csrf():
if current_user.is_authenticated and session.get("auth_version") != current_user.auth_version:
logout_user()
session.clear()
return redirect("/login")
if request.method not in {"POST", "PUT", "PATCH", "DELETE"}:
return None
if validate_csrf_token():