Fix session persistence and improve AJAX detection for file uploads
Fixed three critical issues: 1. Session persistence - Cookies not saved after page refresh - Replaced APPLICATION_ROOT with SESSION_COOKIE_PATH - Added proper cookie settings for reverse proxy (HttpOnly, SameSite) - Set correct cookie path matching URL_PREFIX 2. AJAX detection for FormData uploads (JPG, etc.) - Enhanced @login_required to detect POST/PUT/DELETE as AJAX - Added Content-Type check for JSON requests - Added path prefix check for API endpoints 3. JavaScript AJAX identification - Updated fetchWithAuth() to add X-Requested-With header - Properly handles both JSON and FormData requests using Headers API - Ensures all fetch calls are identified as AJAX by server Changes: - web_app.py: Fixed Flask session cookie configuration - src/auth.py: Improved AJAX detection logic in login_required decorator - templates/index.html: Enhanced fetchWithAuth() with proper headers This fixes: - Users having to re-login on every page refresh - "Unexpected token '<'" errors when uploading JPG files - Session cookies not persisting through reverse proxy Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
53ab780758
commit
2ea4673bf0
3 changed files with 32 additions and 4 deletions
|
|
@ -30,8 +30,13 @@ def login_required(f):
|
|||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
# Check if request is AJAX/API call
|
||||
is_ajax = request.headers.get('X-Requested-With') == 'XMLHttpRequest' or \
|
||||
'application/json' in request.headers.get('Accept', '')
|
||||
# Also check for POST/PUT/DELETE methods which are typically API calls
|
||||
is_ajax = (
|
||||
request.headers.get('X-Requested-With') == 'XMLHttpRequest' or
|
||||
'application/json' in request.headers.get('Accept', '') or
|
||||
request.headers.get('Content-Type', '').startswith('application/json') or
|
||||
(request.method in ['POST', 'PUT', 'DELETE'] and request.path.startswith(URL_PREFIX))
|
||||
)
|
||||
|
||||
if 'user_id' not in session:
|
||||
# Return JSON for AJAX requests, redirect for normal requests
|
||||
|
|
|
|||
|
|
@ -996,6 +996,24 @@
|
|||
// Helper function to handle fetch with authentication check
|
||||
async function fetchWithAuth(url, options = {}) {
|
||||
try {
|
||||
// Add X-Requested-With header to identify AJAX requests
|
||||
// Use Headers object to properly handle both JSON and FormData requests
|
||||
if (!options.headers) {
|
||||
options.headers = {};
|
||||
}
|
||||
|
||||
// Convert to Headers object if it's a plain object
|
||||
if (!(options.headers instanceof Headers)) {
|
||||
const headers = new Headers();
|
||||
for (const [key, value] of Object.entries(options.headers)) {
|
||||
headers.append(key, value);
|
||||
}
|
||||
headers.append('X-Requested-With', 'XMLHttpRequest');
|
||||
options.headers = headers;
|
||||
} else {
|
||||
options.headers.append('X-Requested-With', 'XMLHttpRequest');
|
||||
}
|
||||
|
||||
const response = await fetch(url, options);
|
||||
|
||||
// Check for authentication error
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@ app.config['MAX_CONTENT_LENGTH'] = 500 * 1024 * 1024 # 500MB max file size
|
|||
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)
|
||||
# URL prefix for reverse proxy redirects
|
||||
URL_PREFIX = os.getenv('URL_PREFIX', '/solventum-image-metadata')
|
||||
# APPLICATION_ROOT sets cookie path for reverse proxy setups
|
||||
app.config['APPLICATION_ROOT'] = os.getenv('APPLICATION_ROOT', '/solventum-image-metadata')
|
||||
|
||||
# Docker mode detection
|
||||
DOCKER_MODE = os.getenv('DOCKER_MODE', 'false').lower() == 'true'
|
||||
|
|
@ -75,7 +73,14 @@ else:
|
|||
# Use temp directory for local development
|
||||
app.config['UPLOAD_FOLDER'] = tempfile.mkdtemp()
|
||||
|
||||
# Session configuration
|
||||
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', secrets.token_hex(32))
|
||||
# Cookie settings for reverse proxy
|
||||
app.config['SESSION_COOKIE_PATH'] = URL_PREFIX
|
||||
app.config['SESSION_COOKIE_HTTPONLY'] = True
|
||||
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
|
||||
# Set Secure flag only for HTTPS (production)
|
||||
app.config['SESSION_COOKIE_SECURE'] = os.getenv('FLASK_ENV') == 'production'
|
||||
|
||||
# Excel file path for metadata lookup
|
||||
EXCEL_PATH = Path(__file__).parent / "Celum ID to Adobe Asset Path Mapping Spreadsheet (1).xlsx"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue