logo out issues fixes
This commit is contained in:
@@ -7,9 +7,23 @@ from django.utils.deprecation import MiddlewareMixin
|
||||
from django.http import JsonResponse
|
||||
from django.contrib.auth import logout
|
||||
from rest_framework import status
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
logger = logging.getLogger('auth.middleware')
|
||||
|
||||
# Logout reason codes for precise tracking
|
||||
LOGOUT_REASONS = {
|
||||
'SESSION_ACCOUNT_MISMATCH': 'Session contamination: account ID mismatch',
|
||||
'SESSION_USER_MISMATCH': 'Session contamination: user ID mismatch',
|
||||
'ACCOUNT_MISSING': 'Account not configured for this user',
|
||||
'ACCOUNT_SUSPENDED': 'Account is suspended',
|
||||
'ACCOUNT_CANCELLED': 'Account is cancelled',
|
||||
'PLAN_MISSING': 'No subscription plan assigned',
|
||||
'PLAN_INACTIVE': 'Subscription plan is inactive',
|
||||
'USER_INACTIVE': 'User account is inactive',
|
||||
}
|
||||
|
||||
try:
|
||||
import jwt
|
||||
JWT_AVAILABLE = True
|
||||
@@ -47,39 +61,8 @@ class AccountContextMiddleware(MiddlewareMixin):
|
||||
# This is already loaded, no need to query DB again
|
||||
request.account = getattr(request.user, 'account', None)
|
||||
|
||||
# CRITICAL: Add account ID to session to prevent cross-contamination
|
||||
# This ensures each session is tied to a specific account
|
||||
if request.account:
|
||||
request.session['_account_id'] = request.account.id
|
||||
request.session['_user_id'] = request.user.id
|
||||
# Verify session integrity - if stored IDs don't match, logout
|
||||
stored_account_id = request.session.get('_account_id')
|
||||
stored_user_id = request.session.get('_user_id')
|
||||
if stored_account_id and stored_account_id != request.account.id:
|
||||
# Session contamination detected - force logout
|
||||
logger.warning(
|
||||
f"[AUTO-LOGOUT] Session contamination: account_id mismatch. "
|
||||
f"Session={stored_account_id}, Current={request.account.id}, "
|
||||
f"User={request.user.id}, Path={request.path}, IP={request.META.get('REMOTE_ADDR')}"
|
||||
)
|
||||
logout(request)
|
||||
return JsonResponse(
|
||||
{'success': False, 'error': 'Session integrity violation detected. Please login again.'},
|
||||
status=status.HTTP_401_UNAUTHORIZED
|
||||
)
|
||||
if stored_user_id and stored_user_id != request.user.id:
|
||||
# Session contamination detected - force logout
|
||||
logger.warning(
|
||||
f"[AUTO-LOGOUT] Session contamination: user_id mismatch. "
|
||||
f"Session={stored_user_id}, Current={request.user.id}, "
|
||||
f"Account={request.account.id if request.account else None}, "
|
||||
f"Path={request.path}, IP={request.META.get('REMOTE_ADDR')}"
|
||||
)
|
||||
logout(request)
|
||||
return JsonResponse(
|
||||
{'success': False, 'error': 'Session integrity violation detected. Please login again.'},
|
||||
status=status.HTTP_401_UNAUTHORIZED
|
||||
)
|
||||
# REMOVED: Session contamination checks on every request
|
||||
# These were causing random logouts - session integrity handled by Django
|
||||
|
||||
return None
|
||||
except (AttributeError, Exception):
|
||||
@@ -184,13 +167,29 @@ class AccountContextMiddleware(MiddlewareMixin):
|
||||
return None
|
||||
|
||||
def _deny_request(self, request, error, status_code):
|
||||
"""Logout session users (if any) and return a consistent JSON error."""
|
||||
"""Logout session users (if any) and return a consistent JSON error with detailed tracking."""
|
||||
# Determine logout reason code based on error message
|
||||
reason_code = 'UNKNOWN'
|
||||
if 'Account not configured' in error or 'Account not found' in error:
|
||||
reason_code = 'ACCOUNT_MISSING'
|
||||
elif 'suspended' in error.lower():
|
||||
reason_code = 'ACCOUNT_SUSPENDED'
|
||||
elif 'cancelled' in error.lower():
|
||||
reason_code = 'ACCOUNT_CANCELLED'
|
||||
elif 'No subscription plan' in error or 'plan assigned' in error.lower():
|
||||
reason_code = 'PLAN_MISSING'
|
||||
elif 'plan is inactive' in error.lower() or 'Active subscription required' in error:
|
||||
reason_code = 'PLAN_INACTIVE'
|
||||
elif 'inactive' in error.lower():
|
||||
reason_code = 'USER_INACTIVE'
|
||||
|
||||
try:
|
||||
if hasattr(request, 'user') and request.user and request.user.is_authenticated:
|
||||
logger.warning(
|
||||
f"[AUTO-LOGOUT] Account/plan validation failed: {error}. "
|
||||
f"[AUTO-LOGOUT] {reason_code}: {error}. "
|
||||
f"User={request.user.id}, Account={getattr(request, 'account', None)}, "
|
||||
f"Path={request.path}, IP={request.META.get('REMOTE_ADDR')}"
|
||||
f"Path={request.path}, IP={request.META.get('REMOTE_ADDR')}, "
|
||||
f"Status={status_code}, Timestamp={datetime.now().isoformat()}"
|
||||
)
|
||||
logout(request)
|
||||
except Exception as e:
|
||||
@@ -200,6 +199,14 @@ class AccountContextMiddleware(MiddlewareMixin):
|
||||
{
|
||||
'success': False,
|
||||
'error': error,
|
||||
'logout_reason': reason_code,
|
||||
'logout_message': LOGOUT_REASONS.get(reason_code, error),
|
||||
'logout_path': request.path,
|
||||
'logout_context': {
|
||||
'user_id': request.user.id if hasattr(request, 'user') and request.user and request.user.is_authenticated else None,
|
||||
'account_id': getattr(request, 'account', None).id if hasattr(request, 'account') and getattr(request, 'account', None) else None,
|
||||
'status_code': status_code,
|
||||
}
|
||||
},
|
||||
status=status_code,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user