diff --git a/auth.py b/auth.py new file mode 100644 index 0000000..b3a8379 --- /dev/null +++ b/auth.py @@ -0,0 +1,62 @@ +""" +ParamHub 认证模块 +提供登录/登出功能和 require_auth 装饰器 +密码存储在 config.json 的 admin_password 字段,默认为 admin123 +""" +from functools import wraps +from flask import Blueprint, render_template, request, redirect, url_for, session, jsonify + +from utils import load_config + +auth_bp = Blueprint('auth', __name__) + + +def _check_password(password: str) -> bool: + """验证管理员密码""" + config = load_config() + stored = config.get('admin_password', 'admin123') + return password == stored + + +def require_auth(f): + """装饰器:要求已登录才能访问""" + + @wraps(f) + def decorated(*args, **kwargs): + if not session.get('authenticated'): + # API 请求返回 401,页面请求重定向到登录页 + if request.path.startswith('/api/'): + return jsonify({'error': '未登录', 'redirect': '/login'}), 401 + return redirect(url_for('auth.login_page')) + return f(*args, **kwargs) + + return decorated + + +@auth_bp.route('/login', methods=['GET']) +def login_page(): + """登录页面""" + if session.get('authenticated'): + return redirect(url_for('admin_page')) + return render_template('login.html') + + +@auth_bp.route('/login', methods=['POST']) +def login(): + """处理登录请求""" + data = request.get_json() if request.is_json else request.form + password = data.get('password', '') if request.is_json else request.form.get('password', '') + + if _check_password(password): + session['authenticated'] = True + session.permanent = True + return jsonify({'success': True, 'redirect': '/admin'}) + + return jsonify({'success': False, 'error': '密码错误'}), 401 + + +@auth_bp.route('/logout') +def logout(): + """登出""" + session.clear() + return redirect(url_for('auth.login_page'))