This commit is contained in:
2026-05-01 02:01:30 +08:00
parent 0b2199ec49
commit ced6c67e83
7 changed files with 218 additions and 104 deletions

View File

@@ -32,9 +32,28 @@ def login():
remember = bool(request.form.get('remember'))
merge_data = bool(request.form.get('merge_data'))
if user and check_password_hash(user.password_hash, password):
login_user(user, remember=remember)
from app.models import UserSession
session_token = str(uuid.uuid4())
# 尝试获取反向代理传递的真实 IP
client_ip = request.headers.get('X-Real-IP')
if not client_ip:
client_ip = request.remote_addr
user_session = UserSession(
user_id=user.id,
session_token=session_token,
ip_address=client_ip,
user_agent=request.user_agent.string
)
db.session.add(user_session)
db.session.commit()
session['user_session_token'] = session_token
if merge_data:
guest_id = request.cookies.get('guest_id')
if guest_id:
@@ -110,10 +129,20 @@ def login():
flash('Invalid username or password', 'danger')
return render_template('auth/login.html')
@auth_bp.route('/logout')
@login_required
def logout():
session_token = session.get('user_session_token')
if session_token:
from app.models import UserSession
user_session = UserSession.query.filter_by(session_token=session_token).first()
if user_session:
user_session.is_active = False
db.session.commit()
logout_user()
session.pop('user_session_token', None)
response = make_response(redirect(url_for('main.index')))
response.delete_cookie('guest_id') # Optionally clear guest cookie
return response

View File

@@ -18,6 +18,24 @@ from app.routes.admin_routes import get_gcode_dir
main_bp = Blueprint('main', __name__)
@main_bp.before_app_request
def check_user_session():
if current_user.is_authenticated and not current_user.is_guest:
from app.models import UserSession
session_token = session.get('user_session_token')
if session_token:
user_session = UserSession.query.filter_by(session_token=session_token).first()
if not user_session or not user_session.is_active:
from flask_login import logout_user
logout_user()
session.pop('user_session_token', None)
flash('Your session has been terminated.', 'warning')
return redirect(url_for('auth.login'))
else:
user_session.last_active = datetime.utcnow()
db.session.commit()
auth_bp = Blueprint('auth', __name__, url_prefix='/auth')
admin_bp = Blueprint('admin', __name__, url_prefix='/admin')
@@ -562,3 +580,52 @@ def engine_options(engine_name):
patterns = engine.get_support_patterns(current_app)
materials = engine.get_materials(current_app) if hasattr(engine, 'get_materials') else []
return jsonify({'presets': presets, 'support_patterns': patterns, 'materials': materials})
@main_bp.route('/account', methods=['GET', 'POST'])
@login_required
def account():
if current_user.is_guest:
flash('Guests cannot manage accounts.', 'danger')
return redirect(url_for('main.index'))
from app.models import UserSession
if request.method == 'POST':
action = request.form.get('action')
if action == 'change_password':
current_pass = request.form.get('current_password')
new_pass = request.form.get('new_password')
confirm_pass = request.form.get('confirm_password')
if not check_password_hash(current_user.password_hash, current_pass):
flash('Current password is incorrect.', 'danger')
elif new_pass != confirm_pass:
flash('New passwords do not match.', 'danger')
elif len(new_pass) < 6:
flash('New password must be at least 6 characters.', 'danger')
else:
current_user.password_hash = generate_password_hash(new_pass)
db.session.commit()
flash('Password updated successfully.', 'success')
elif action == 'terminate_session':
session_id = request.form.get('session_id')
token_to_terminate = request.form.get('session_token')
my_session_token = session.get('user_session_token')
if token_to_terminate == my_session_token:
flash('You cannot terminate your current session from here. Please logout instead.', 'warning')
else:
us = UserSession.query.filter_by(id=session_id, user_id=current_user.id).first()
if us:
us.is_active = False
db.session.commit()
flash('Session terminated.', 'success')
return redirect(url_for('main.account'))
sessions = UserSession.query.filter_by(user_id=current_user.id, is_active=True).order_by(UserSession.last_active.desc()).all()
current_token = session.get('user_session_token')
return render_template('slice/account.html', sessions=sessions, current_token=current_token)