This commit is contained in:
Mateusz Gruszczyński
2025-11-04 10:30:28 +01:00
parent 398ccce3b5
commit 577dc789fc

View File

@@ -1,10 +1,9 @@
"""Authentication routes - Login, Logout, Register""" """Authentication routes - Login, Logout"""
from flask import Blueprint, render_template, request, redirect, url_for, session, jsonify, flash from flask import Blueprint, render_template, request, redirect, url_for, session, jsonify
from functools import wraps from functools import wraps
from database import db from database import db
from database.models import User from database.models import User
from datetime import datetime
import logging import logging
auth_bp = Blueprint('auth', __name__) auth_bp = Blueprint('auth', __name__)
@@ -12,91 +11,94 @@ logger = logging.getLogger(__name__)
def login_required(f): def login_required(f):
"""Decorator to require login""" """Decorator - require user to be logged in"""
@wraps(f)
def decorated_function(*args, **kwargs):
if 'user_id' not in session:
return redirect(url_for('auth.login', next=request.url))
return f(*args, **kwargs)
return decorated_function
def admin_required(f):
"""Decorator to require admin role"""
@wraps(f) @wraps(f)
def decorated_function(*args, **kwargs): def decorated_function(*args, **kwargs):
if 'user_id' not in session: if 'user_id' not in session:
return redirect(url_for('auth.login')) return redirect(url_for('auth.login'))
user = User.query.get(session['user_id'])
if not user or not user.is_admin:
flash('Admin access required', 'danger')
return redirect(url_for('main.index'))
return f(*args, **kwargs) return f(*args, **kwargs)
return decorated_function return decorated_function
@auth_bp.route('/login', methods=['GET', 'POST']) @auth_bp.route('/login', methods=['GET', 'POST'])
def login(): def login():
"""Login page""" """Login page and authentication"""
if request.method == 'POST': if request.method == 'GET':
username = request.form.get('username') if 'user_id' in session:
password = request.form.get('password') return redirect(url_for('main.index'))
return render_template('auth/login.html')
# POST - process login
username = request.form.get('username', '').strip()
password = request.form.get('password', '').strip()
if not username or not password: if not username or not password:
flash('Username and password required', 'warning') return render_template('auth/login.html', error='Username and password required'), 400
return redirect(url_for('auth.login'))
try:
# Find user
user = User.query.filter_by(username=username).first() user = User.query.filter_by(username=username).first()
if user and user.check_password(password): if not user:
logger.warning(f"[AUTH] Login failed - user '{username}' not found", flush=True)
return render_template('auth/login.html', error='Invalid credentials'), 401
# Check password
if not user.check_password(password):
logger.warning(f"[AUTH] Login failed - wrong password for '{username}'", flush=True)
return render_template('auth/login.html', error='Invalid credentials'), 401
session.clear()
session['user_id'] = user.id session['user_id'] = user.id
session['username'] = user.username session['username'] = user.username
session['is_admin'] = user.is_admin session['is_admin'] = user.is_admin
session.permanent = True session.permanent = True
from datetime import datetime
user.last_login = datetime.utcnow() user.last_login = datetime.utcnow()
db.session.commit() db.session.commit()
logger.info(f"[AUTH] User '{username}' logged in", flush=True) logger.info(f"[AUTH] User '{username}' logged in successfully", flush=True)
next_page = request.args.get('next')
if next_page and next_page.startswith('/'):
return redirect(next_page)
return redirect(url_for('main.index')) return redirect(url_for('main.index'))
logger.warning(f"[AUTH] Failed login attempt for '{username}'", flush=True) except Exception as e:
flash('Invalid username or password', 'danger') logger.error(f"[AUTH] Login error: {e}", flush=True)
return render_template('auth/login.html', error='Login error'), 500
return render_template('login.html')
@auth_bp.route('/logout') @auth_bp.route('/logout', methods=['GET', 'POST'])
def logout(): def logout():
"""Logout""" """Logout"""
username = session.get('username', 'Unknown') username = session.get('username', 'unknown')
session.clear() session.clear()
logger.info(f"[AUTH] User '{username}' logged out", flush=True) logger.info(f"[AUTH] User '{username}' logged out", flush=True)
flash('You have been logged out', 'info')
return redirect(url_for('auth.login')) return redirect(url_for('auth.login'))
@auth_bp.route('/api/current-user') @auth_bp.route('/api/current-user', methods=['GET'])
def api_current_user(): def current_user():
"""Get current user info (API)""" """Get current logged in user info"""
if 'user_id' not in session: if 'user_id' not in session:
return jsonify({'error': 'Not authenticated'}), 401 return jsonify({'error': 'Not authenticated', 'success': False}), 401
try:
user = User.query.get(session['user_id']) user = User.query.get(session['user_id'])
if not user: if not user:
session.clear() session.clear()
return jsonify({'error': 'User not found'}), 404 return jsonify({'error': 'User not found', 'success': False}), 401
return jsonify({ return jsonify({
'success': True,
'user': {
'id': user.id, 'id': user.id,
'username': user.username, 'username': user.username,
'is_admin': user.is_admin, 'is_admin': user.is_admin
'created_at': user.created_at.isoformat() if user.created_at else None, }
'last_login': user.last_login.isoformat() if user.last_login else None
}) })
except Exception as e:
logger.error(f"[AUTH] Error getting current user: {e}", flush=True)
return jsonify({'error': str(e), 'success': False}), 500