from datetime import datetime from flask import Blueprint, render_template, redirect, url_for, flash, request, make_response, current_app from flask_login import login_user, logout_user, login_required, current_user from werkzeug.security import check_password_hash import jwt from app.extensions import db from app.models.user import PortalUser bp = Blueprint('auth', __name__) def _issue_portal_cookie(user, response): """Sign and attach the platform-wide JWT cookie to a response.""" import time expiry_hours = current_app.config['JWT_EXPIRY_HOURS'] now = int(time.time()) payload = { 'sub': user.username, 'user_id': user.id, 'email': user.email, 'role': 'admin' if user.is_admin else 'user', 'apps': user.get_accessible_apps(), 'iss': 'enterprise-digital-platform', 'iat': now, 'exp': now + expiry_hours * 3600, } token = jwt.encode(payload, current_app.config['PORTAL_JWT_SECRET'], algorithm='HS256') response.set_cookie( current_app.config['PORTAL_COOKIE_NAME'], token, httponly=True, samesite='Lax', max_age=expiry_hours * 3600, path='/', ) return response @bp.route('/login', methods=['GET', 'POST']) def login(): if current_user.is_authenticated: return redirect(url_for('dashboard.index')) if request.method == 'POST': username = request.form.get('username', '').strip() password = request.form.get('password', '') if not username or not password: flash('Please enter username and password.', 'danger') return render_template('auth/login.html') user = PortalUser.query.filter_by(username=username, is_active=True).first() if user and check_password_hash(user.password_hash, password): user.last_login = datetime.utcnow() db.session.commit() login_user(user, remember=False) next_page = request.args.get('next') or url_for('dashboard.index') resp = make_response(redirect(next_page)) _issue_portal_cookie(user, resp) return resp flash('Invalid username or password.', 'danger') return render_template('auth/login.html') @bp.route('/logout') @login_required def logout(): logout_user() resp = make_response(redirect(url_for('auth.login'))) resp.delete_cookie(current_app.config['PORTAL_COOKIE_NAME'], path='/') flash('You have been signed out.', 'info') return resp