Session-Timeout nach 5min.
Dieser Commit ist enthalten in:
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
import psycopg2
|
||||
from psycopg2.extras import Json
|
||||
from flask import Flask, render_template, request, redirect, session, url_for, send_file, jsonify
|
||||
from flask import Flask, render_template, request, redirect, session, url_for, send_file, jsonify, flash
|
||||
from flask_session import Session
|
||||
from functools import wraps
|
||||
from dotenv import load_dotenv
|
||||
@@ -25,6 +25,13 @@ app.config['SECRET_KEY'] = os.urandom(24)
|
||||
app.config['SESSION_TYPE'] = 'filesystem'
|
||||
app.config['JSON_AS_ASCII'] = False # JSON-Ausgabe mit UTF-8
|
||||
app.config['JSONIFY_MIMETYPE'] = 'application/json; charset=utf-8'
|
||||
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(minutes=5) # 5 Minuten Session-Timeout
|
||||
app.config['SESSION_COOKIE_HTTPONLY'] = True
|
||||
app.config['SESSION_COOKIE_SECURE'] = False # Wird auf True gesetzt wenn HTTPS (intern läuft HTTP)
|
||||
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
|
||||
app.config['SESSION_COOKIE_NAME'] = 'admin_session'
|
||||
# WICHTIG: Session-Cookie soll auch nach 5 Minuten ablaufen
|
||||
app.config['SESSION_REFRESH_EACH_REQUEST'] = False
|
||||
Session(app)
|
||||
|
||||
# Backup-Konfiguration
|
||||
@@ -57,6 +64,32 @@ def login_required(f):
|
||||
def decorated_function(*args, **kwargs):
|
||||
if 'logged_in' not in session:
|
||||
return redirect(url_for('login'))
|
||||
|
||||
# Prüfe ob Session abgelaufen ist
|
||||
if 'last_activity' in session:
|
||||
last_activity = datetime.fromisoformat(session['last_activity'])
|
||||
time_since_activity = datetime.now() - last_activity
|
||||
|
||||
# Debug-Logging
|
||||
app.logger.info(f"Session check for {session.get('username', 'unknown')}: "
|
||||
f"Last activity: {last_activity}, "
|
||||
f"Time since: {time_since_activity.total_seconds()} seconds")
|
||||
|
||||
if time_since_activity > timedelta(minutes=5):
|
||||
# Session abgelaufen - Logout
|
||||
username = session.get('username', 'unbekannt')
|
||||
app.logger.info(f"Session timeout for user {username} - auto logout")
|
||||
# Audit-Log für automatischen Logout (vor session.clear()!)
|
||||
try:
|
||||
log_audit('AUTO_LOGOUT', 'session', additional_info={'reason': 'Session timeout (5 minutes)', 'username': username})
|
||||
except:
|
||||
pass
|
||||
session.clear()
|
||||
flash('Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.', 'warning')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
# Aktivität NICHT automatisch aktualisieren
|
||||
# Nur bei expliziten Benutzeraktionen (wird vom Heartbeat gemacht)
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
@@ -533,8 +566,10 @@ def login():
|
||||
|
||||
if login_success:
|
||||
# Erfolgreicher Login
|
||||
session.permanent = True # Aktiviert das Timeout
|
||||
session['logged_in'] = True
|
||||
session['username'] = username
|
||||
session['last_activity'] = datetime.now().isoformat()
|
||||
reset_login_attempts(ip_address)
|
||||
log_audit('LOGIN_SUCCESS', 'user',
|
||||
additional_info=f"Erfolgreiche Anmeldung von IP: {ip_address}")
|
||||
@@ -569,6 +604,21 @@ def logout():
|
||||
session.pop('username', None)
|
||||
return redirect(url_for('login'))
|
||||
|
||||
@app.route("/heartbeat", methods=['POST'])
|
||||
@login_required
|
||||
def heartbeat():
|
||||
"""Endpoint für Session Keep-Alive - aktualisiert last_activity"""
|
||||
# Aktualisiere last_activity nur wenn explizit angefordert
|
||||
session['last_activity'] = datetime.now().isoformat()
|
||||
# Force session save
|
||||
session.modified = True
|
||||
|
||||
return jsonify({
|
||||
'status': 'ok',
|
||||
'last_activity': session['last_activity'],
|
||||
'username': session.get('username')
|
||||
})
|
||||
|
||||
@app.route("/")
|
||||
@login_required
|
||||
def dashboard():
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren