kkt-2002 commited on
Commit
b2b104d
·
1 Parent(s): d26dd48

Complete session fix for Hugging Face deployment

Browse files
Files changed (1) hide show
  1. app.py +67 -50
app.py CHANGED
@@ -1,5 +1,4 @@
1
  from flask import Flask, render_template, request, redirect, url_for, flash, session, jsonify
2
- from flask_session import Session
3
  from werkzeug.middleware.proxy_fix import ProxyFix
4
  import os
5
  import gc
@@ -43,19 +42,20 @@ load_dotenv()
43
  # Initialize Flask app
44
  app = Flask(__name__, static_folder='app/static', template_folder='app/templates')
45
 
46
- # CRITICAL FIX: Set consistent SECRET_KEY
47
- app.secret_key = os.environ.get('SECRET_KEY', 'your-very-secure-secret-key-change-in-production')
48
 
49
- # CRITICAL FIX: Use Flask's built-in signed cookie sessions
50
  app.config.update({
51
  'PERMANENT_SESSION_LIFETIME': timedelta(hours=2),
52
- 'SESSION_COOKIE_NAME': 'session',
53
  'SESSION_COOKIE_HTTPONLY': True,
54
- 'SESSION_COOKIE_SECURE': False,
55
- 'SESSION_COOKIE_SAMESITE': 'Lax',
56
- 'SESSION_REFRESH_EACH_REQUEST': True,
57
  'SESSION_COOKIE_DOMAIN': None,
58
- 'SESSION_COOKIE_PATH': '/'
 
59
  })
60
 
61
  # CRITICAL FIX: Add ProxyFix middleware for Hugging Face reverse proxy
@@ -69,7 +69,6 @@ app.wsgi_app = ProxyFix(
69
 
70
  print("Flask app initialized with ProxyFix middleware and built-in cookie sessions")
71
 
72
-
73
  # Create temporary directory for image processing
74
  TEMP_DIR = tempfile.mkdtemp()
75
 
@@ -561,6 +560,8 @@ def login():
561
 
562
  print(f"=== LOGIN DEBUG ===")
563
  print(f"Student ID: {student_id}")
 
 
564
 
565
  if not student_id or not password:
566
  flash('Student ID and password are required.', 'danger')
@@ -570,18 +571,34 @@ def login():
570
  print(f"Student found: {bool(student)}")
571
 
572
  if student and student.get('password') == password:
573
- # CRITICAL FIX: Simplified session setting
574
  session.clear()
 
 
575
  session['logged_in'] = True
576
  session['user_type'] = 'student'
577
  session['student_id'] = student_id
578
  session['name'] = student.get('name', 'Unknown')
 
579
 
580
  print(f"Session after setting: {dict(session)}")
 
 
 
581
  flash('Login successful!', 'success')
582
 
583
- # Direct redirect without manual session saving
584
- return redirect(url_for('dashboard'))
 
 
 
 
 
 
 
 
 
 
585
  else:
586
  print("Invalid credentials")
587
  flash('Invalid credentials. Please try again.', 'danger')
@@ -592,7 +609,6 @@ def login():
592
  flash(f'Login failed: {str(e)}', 'danger')
593
  return redirect(url_for('login_page'))
594
 
595
-
596
  @app.route('/face-login', methods=['POST'])
597
  def face_login():
598
  try:
@@ -647,10 +663,12 @@ def face_login():
647
  if result["verified"]:
648
  # CRITICAL FIX: Simplified session setting
649
  session.clear()
 
650
  session['logged_in'] = True
651
  session['user_type'] = face_role
652
  session[id_field] = user[id_field]
653
  session['name'] = user.get('name', 'Unknown')
 
654
 
655
  print(f"Face login successful for {user.get('name')}, Session: {dict(session)}")
656
  flash('Face login successful!', 'success')
@@ -689,7 +707,6 @@ def face_login():
689
  flash(f'Face login failed: {str(e)}', 'danger')
690
  return redirect(url_for('login_page'))
691
 
692
-
693
  @app.route('/auto-face-login', methods=['POST'])
694
  def auto_face_login():
695
  """Enhanced auto face login with role support"""
@@ -740,14 +757,12 @@ def auto_face_login():
740
  if result["verified"]:
741
  # Clear any existing session
742
  session.clear()
743
-
744
- # Set session variables with Flask-Session
745
  session['logged_in'] = True
746
  session['user_type'] = face_role
747
  session[id_field] = user[id_field]
748
  session['name'] = user.get('name', 'Unknown')
749
- session.permanent = True
750
- session.modified = True
751
 
752
  print(f"Auto face login successful for {user.get('name')}, Session: {dict(session)}")
753
 
@@ -797,25 +812,33 @@ def attendance_page():
797
  @app.route('/dashboard')
798
  def dashboard():
799
  print(f"=== DASHBOARD DEBUG ===")
 
 
800
  print(f"Session data: {dict(session)}")
801
  print(f"Session keys: {list(session.keys())}")
 
 
 
802
 
803
- # Check session data
804
  logged_in = session.get('logged_in')
805
  user_type = session.get('user_type')
 
806
 
807
  print(f"logged_in: {logged_in} (type: {type(logged_in)})")
808
  print(f"user_type: {user_type} (type: {type(user_type)})")
 
809
 
810
  if not logged_in or user_type != 'student':
811
  print("=== SESSION CHECK FAILED ===")
 
 
 
 
812
  flash('Please log in to access the dashboard.', 'info')
813
  return redirect(url_for('login_page'))
814
 
815
  try:
816
- student_id = session.get('student_id')
817
- print(f"Loading dashboard for student: {student_id}")
818
-
819
  student = students_collection.find_one({'student_id': student_id})
820
  if not student:
821
  print("Student not found in database")
@@ -840,24 +863,6 @@ def dashboard():
840
  flash(f'Error loading dashboard: {str(e)}', 'danger')
841
  return redirect(url_for('login_page'))
842
 
843
-
844
- # Process face image if exists
845
- if student and 'face_image' in student and student['face_image']:
846
- face_image_base64 = base64.b64encode(student['face_image']).decode('utf-8')
847
- mime_type = student.get('face_image_type', 'image/jpeg')
848
- student['face_image_url'] = f"data:{mime_type};base64,{face_image_base64}"
849
-
850
- # Get attendance records
851
- attendance_records = list(attendance_collection.find({'student_id': student_id}).sort('date', -1))
852
-
853
- print(f"Dashboard loaded successfully for {student.get('name')}")
854
- return render_template('dashboard.html', student=student, attendance_records=attendance_records)
855
-
856
- except Exception as e:
857
- print(f"Dashboard error: {e}")
858
- flash(f'Error loading dashboard: {str(e)}', 'danger')
859
- return redirect(url_for('login_page'))
860
-
861
  @app.route('/mark-attendance', methods=['POST'])
862
  def mark_attendance():
863
  if 'logged_in' not in session or session.get('user_type') != 'student':
@@ -1170,14 +1175,12 @@ def teacher_login():
1170
  if teacher and teacher.get('password') == password:
1171
  # Clear any existing session
1172
  session.clear()
1173
-
1174
- # Set session variables with Flask-Session
1175
  session['logged_in'] = True
1176
  session['user_type'] = 'teacher'
1177
  session['teacher_id'] = teacher_id
1178
  session['name'] = teacher.get('name', 'Unknown')
1179
- session.permanent = True
1180
- session.modified = True
1181
 
1182
  print(f"Teacher session set: {dict(session)}")
1183
  flash('Login successful!', 'success')
@@ -1331,7 +1334,7 @@ def health_check():
1331
  'status': 'healthy',
1332
  'platform': 'hugging_face',
1333
  'session_working': bool(session.get('logged_in')),
1334
- 'session_storage': app.config['SESSION_TYPE'],
1335
  'proxy_fix': 'enabled',
1336
  'session_keys': list(session.keys()),
1337
  'timestamp': datetime.now().isoformat()
@@ -1344,13 +1347,28 @@ def debug_session():
1344
  'session_keys': list(session.keys()),
1345
  'cookies': dict(request.cookies),
1346
  'headers': dict(request.headers),
1347
- 'session_type': app.config['SESSION_TYPE'],
1348
- 'session_dir': app.config['SESSION_FILE_DIR'],
1349
  'proxy_fix': 'enabled',
1350
  'session_modified': getattr(session, 'modified', 'N/A'),
1351
  'session_permanent': getattr(session, 'permanent', 'N/A')
1352
  })
1353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1354
  @app.route('/test-session')
1355
  def test_session():
1356
  """Test session functionality"""
@@ -1358,7 +1376,6 @@ def test_session():
1358
  session['test_data'] = 'working'
1359
  session['timestamp'] = datetime.now().isoformat()
1360
  session.permanent = True
1361
- session.modified = True
1362
 
1363
  return jsonify({
1364
  'message': 'Session test completed',
@@ -1378,5 +1395,5 @@ def manual_cleanup():
1378
  # MAIN APPLICATION ENTRY POINT
1379
  if __name__ == '__main__':
1380
  port = int(os.environ.get('PORT', 7860)) # Hugging Face uses port 7860
1381
- print(f"Starting Flask app on port {port} with ProxyFix middleware and Flask-Session")
1382
  app.run(host='0.0.0.0', port=port, debug=False)
 
1
  from flask import Flask, render_template, request, redirect, url_for, flash, session, jsonify
 
2
  from werkzeug.middleware.proxy_fix import ProxyFix
3
  import os
4
  import gc
 
42
  # Initialize Flask app
43
  app = Flask(__name__, static_folder='app/static', template_folder='app/templates')
44
 
45
+ # CRITICAL FIX: Enhanced secret key and session config for Hugging Face
46
+ app.secret_key = os.environ.get('SECRET_KEY', 'huggingface-face-recognition-super-secret-key-2025')
47
 
48
+ # CRITICAL FIX: Optimized session config for Hugging Face Spaces
49
  app.config.update({
50
  'PERMANENT_SESSION_LIFETIME': timedelta(hours=2),
51
+ 'SESSION_COOKIE_NAME': 'face_app_session',
52
  'SESSION_COOKIE_HTTPONLY': True,
53
+ 'SESSION_COOKIE_SECURE': False, # Hugging Face uses HTTP internally
54
+ 'SESSION_COOKIE_SAMESITE': None, # Critical for Hugging Face iframe
55
+ 'SESSION_REFRESH_EACH_REQUEST': False, # Prevent session reset
56
  'SESSION_COOKIE_DOMAIN': None,
57
+ 'SESSION_COOKIE_PATH': '/',
58
+ 'SEND_FILE_MAX_AGE_DEFAULT': 0 # Disable caching
59
  })
60
 
61
  # CRITICAL FIX: Add ProxyFix middleware for Hugging Face reverse proxy
 
69
 
70
  print("Flask app initialized with ProxyFix middleware and built-in cookie sessions")
71
 
 
72
  # Create temporary directory for image processing
73
  TEMP_DIR = tempfile.mkdtemp()
74
 
 
560
 
561
  print(f"=== LOGIN DEBUG ===")
562
  print(f"Student ID: {student_id}")
563
+ print(f"Request headers: {dict(request.headers)}")
564
+ print(f"User-Agent: {request.headers.get('User-Agent', 'N/A')}")
565
 
566
  if not student_id or not password:
567
  flash('Student ID and password are required.', 'danger')
 
571
  print(f"Student found: {bool(student)}")
572
 
573
  if student and student.get('password') == password:
574
+ # CRITICAL FIX: Clear and set session with permanent flag
575
  session.clear()
576
+ session.permanent = True # Make session permanent FIRST
577
+
578
  session['logged_in'] = True
579
  session['user_type'] = 'student'
580
  session['student_id'] = student_id
581
  session['name'] = student.get('name', 'Unknown')
582
+ session['login_time'] = datetime.now().isoformat()
583
 
584
  print(f"Session after setting: {dict(session)}")
585
+ print(f"Session permanent: {session.permanent}")
586
+ print(f"Session modified: {session.modified}")
587
+
588
  flash('Login successful!', 'success')
589
 
590
+ # Create response and explicitly save session
591
+ response = redirect(url_for('dashboard'))
592
+
593
+ # Add session cookie headers manually for debugging
594
+ response.set_cookie(
595
+ 'debug_session',
596
+ f"logged_in_at_{int(datetime.now().timestamp())}",
597
+ max_age=3600,
598
+ httponly=False
599
+ )
600
+
601
+ return response
602
  else:
603
  print("Invalid credentials")
604
  flash('Invalid credentials. Please try again.', 'danger')
 
609
  flash(f'Login failed: {str(e)}', 'danger')
610
  return redirect(url_for('login_page'))
611
 
 
612
  @app.route('/face-login', methods=['POST'])
613
  def face_login():
614
  try:
 
663
  if result["verified"]:
664
  # CRITICAL FIX: Simplified session setting
665
  session.clear()
666
+ session.permanent = True
667
  session['logged_in'] = True
668
  session['user_type'] = face_role
669
  session[id_field] = user[id_field]
670
  session['name'] = user.get('name', 'Unknown')
671
+ session['login_time'] = datetime.now().isoformat()
672
 
673
  print(f"Face login successful for {user.get('name')}, Session: {dict(session)}")
674
  flash('Face login successful!', 'success')
 
707
  flash(f'Face login failed: {str(e)}', 'danger')
708
  return redirect(url_for('login_page'))
709
 
 
710
  @app.route('/auto-face-login', methods=['POST'])
711
  def auto_face_login():
712
  """Enhanced auto face login with role support"""
 
757
  if result["verified"]:
758
  # Clear any existing session
759
  session.clear()
760
+ session.permanent = True
 
761
  session['logged_in'] = True
762
  session['user_type'] = face_role
763
  session[id_field] = user[id_field]
764
  session['name'] = user.get('name', 'Unknown')
765
+ session['login_time'] = datetime.now().isoformat()
 
766
 
767
  print(f"Auto face login successful for {user.get('name')}, Session: {dict(session)}")
768
 
 
812
  @app.route('/dashboard')
813
  def dashboard():
814
  print(f"=== DASHBOARD DEBUG ===")
815
+ print(f"Request headers: {dict(request.headers)}")
816
+ print(f"Request cookies: {dict(request.cookies)}")
817
  print(f"Session data: {dict(session)}")
818
  print(f"Session keys: {list(session.keys())}")
819
+ print(f"Session permanent: {getattr(session, 'permanent', 'N/A')}")
820
+ print(f"Session modified: {getattr(session, 'modified', 'N/A')}")
821
+ print(f"User-Agent: {request.headers.get('User-Agent', 'N/A')}")
822
 
823
+ # Check each session key individually
824
  logged_in = session.get('logged_in')
825
  user_type = session.get('user_type')
826
+ student_id = session.get('student_id')
827
 
828
  print(f"logged_in: {logged_in} (type: {type(logged_in)})")
829
  print(f"user_type: {user_type} (type: {type(user_type)})")
830
+ print(f"student_id: {student_id} (type: {type(student_id)})")
831
 
832
  if not logged_in or user_type != 'student':
833
  print("=== SESSION CHECK FAILED ===")
834
+ print("Possible causes:")
835
+ print("1. Session cookie not being sent")
836
+ print("2. Session data not persisting")
837
+ print("3. Different user agents between requests")
838
  flash('Please log in to access the dashboard.', 'info')
839
  return redirect(url_for('login_page'))
840
 
841
  try:
 
 
 
842
  student = students_collection.find_one({'student_id': student_id})
843
  if not student:
844
  print("Student not found in database")
 
863
  flash(f'Error loading dashboard: {str(e)}', 'danger')
864
  return redirect(url_for('login_page'))
865
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
866
  @app.route('/mark-attendance', methods=['POST'])
867
  def mark_attendance():
868
  if 'logged_in' not in session or session.get('user_type') != 'student':
 
1175
  if teacher and teacher.get('password') == password:
1176
  # Clear any existing session
1177
  session.clear()
1178
+ session.permanent = True
 
1179
  session['logged_in'] = True
1180
  session['user_type'] = 'teacher'
1181
  session['teacher_id'] = teacher_id
1182
  session['name'] = teacher.get('name', 'Unknown')
1183
+ session['login_time'] = datetime.now().isoformat()
 
1184
 
1185
  print(f"Teacher session set: {dict(session)}")
1186
  flash('Login successful!', 'success')
 
1334
  'status': 'healthy',
1335
  'platform': 'hugging_face',
1336
  'session_working': bool(session.get('logged_in')),
1337
+ 'session_storage': 'built-in_cookies', # Fixed: removed SESSION_TYPE reference
1338
  'proxy_fix': 'enabled',
1339
  'session_keys': list(session.keys()),
1340
  'timestamp': datetime.now().isoformat()
 
1347
  'session_keys': list(session.keys()),
1348
  'cookies': dict(request.cookies),
1349
  'headers': dict(request.headers),
1350
+ 'session_storage': 'built-in_cookies',
 
1351
  'proxy_fix': 'enabled',
1352
  'session_modified': getattr(session, 'modified', 'N/A'),
1353
  'session_permanent': getattr(session, 'permanent', 'N/A')
1354
  })
1355
 
1356
+ @app.route('/debug-session-detailed')
1357
+ def debug_session_detailed():
1358
+ return jsonify({
1359
+ 'session_data': dict(session),
1360
+ 'session_keys': list(session.keys()),
1361
+ 'cookies_received': dict(request.cookies),
1362
+ 'headers': dict(request.headers),
1363
+ 'user_agent': request.headers.get('User-Agent'),
1364
+ 'remote_addr': request.remote_addr,
1365
+ 'session_permanent': getattr(session, 'permanent', 'N/A'),
1366
+ 'session_modified': getattr(session, 'modified', 'N/A'),
1367
+ 'flask_secret_key_length': len(app.secret_key),
1368
+ 'session_interface_type': str(type(app.session_interface)),
1369
+ 'timestamp': datetime.now().isoformat()
1370
+ })
1371
+
1372
  @app.route('/test-session')
1373
  def test_session():
1374
  """Test session functionality"""
 
1376
  session['test_data'] = 'working'
1377
  session['timestamp'] = datetime.now().isoformat()
1378
  session.permanent = True
 
1379
 
1380
  return jsonify({
1381
  'message': 'Session test completed',
 
1395
  # MAIN APPLICATION ENTRY POINT
1396
  if __name__ == '__main__':
1397
  port = int(os.environ.get('PORT', 7860)) # Hugging Face uses port 7860
1398
+ print(f"Starting Flask app on port {port} with ProxyFix middleware and built-in sessions")
1399
  app.run(host='0.0.0.0', port=port, debug=False)