Fix admin authentication in production environment with persistent sessions

This commit is contained in:
hex
2025-05-20 19:06:08 -07:00
parent 601f4180ae
commit 7d441068dc
3 changed files with 59 additions and 1 deletions

View File

@@ -10,16 +10,60 @@ load_dotenv()
# Initialize SQLAlchemy # Initialize SQLAlchemy
db = SQLAlchemy() db = SQLAlchemy()
# Get or generate a stable SECRET_KEY
def get_secret_key():
# Check for an existing key file
key_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../instance/secret_key')
# If running in production with Docker, store in a more appropriate location
if os.environ.get('FLASK_ENV') == 'production':
key_file = '/data/secret_key'
try:
# Try to read existing key
if os.path.exists(key_file):
with open(key_file, 'rb') as f:
key = f.read()
if key:
return key
except:
pass
# Generate a new key
key = secrets.token_hex(32).encode()
# Try to save it for future use
try:
os.makedirs(os.path.dirname(key_file), exist_ok=True)
with open(key_file, 'wb') as f:
f.write(key)
except:
# If we can't save it, just use it for this session
pass
return key
def create_app(): def create_app():
app = Flask(__name__, instance_relative_config=True) app = Flask(__name__, instance_relative_config=True)
# Determine if we're in production
is_production = os.environ.get('FLASK_ENV') == 'production'
# Configure the app # Configure the app
app.config.from_mapping( app.config.from_mapping(
SECRET_KEY=os.environ.get('SECRET_KEY', secrets.token_hex(16)), SECRET_KEY=os.environ.get('SECRET_KEY', get_secret_key()),
SQLALCHEMY_DATABASE_URI=f"sqlite:///{os.path.join(app.instance_path, 'game_tracker.sqlite')}", SQLALCHEMY_DATABASE_URI=f"sqlite:///{os.path.join(app.instance_path, 'game_tracker.sqlite')}",
SQLALCHEMY_TRACK_MODIFICATIONS=False, SQLALCHEMY_TRACK_MODIFICATIONS=False,
# Session configuration for secure cookies
SESSION_COOKIE_SECURE=is_production, # Only send cookies over HTTPS in production
SESSION_COOKIE_HTTPONLY=True, # Prevent JavaScript access to cookies
SESSION_COOKIE_SAMESITE='Lax', # Prevent CSRF attacks
PERMANENT_SESSION_LIFETIME=86400, # 24 hours
) )
# If behind a proxy (like Nginx), trust the proxy headers
app.config['PREFERRED_URL_SCHEME'] = 'https' if is_production else 'http'
# Ensure the instance folder exists # Ensure the instance folder exists
try: try:
os.makedirs(app.instance_path) os.makedirs(app.instance_path)
@@ -33,6 +77,14 @@ def create_app():
from .routes import main_bp from .routes import main_bp
app.register_blueprint(main_bp) app.register_blueprint(main_bp)
# Set up session persistence for production
if is_production:
from flask_session import Session
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = '/data/flask_session'
app.config['SESSION_PERMANENT'] = True
Session(app)
# Create database tables # Create database tables
with app.app_context(): with app.app_context():
db.create_all() db.create_all()

View File

@@ -7,8 +7,12 @@ services:
- "8000" - "8000"
volumes: volumes:
- ./instance:/app/instance - ./instance:/app/instance
- ./data/flask_session:/data/flask_session
- ./data/secrets:/data
env_file: env_file:
- .env - .env
environment:
- FLASK_ENV=production
restart: unless-stopped restart: unless-stopped
networks: networks:
- app-network - app-network

View File

@@ -1,5 +1,7 @@
Flask==2.3.3 Flask==2.3.3
Flask-SQLAlchemy==3.1.1 Flask-SQLAlchemy==3.1.1
Flask-WTF==1.2.1 Flask-WTF==1.2.1
Flask-Session==0.5.0
requests==2.31.0 requests==2.31.0
python-dotenv==1.0.0 python-dotenv==1.0.0
gunicorn==21.2.0