from functools import wraps from flask import request, jsonify, redirect, url_for, flash, abort, g from flask_login import current_user def require_permission(module: str, min_level: str = 'read'): """ Decorador de seguridad declarativa a nivel de método inspirado en @PreAuthorize de Spring Security. Verifica los privilegios del usuario autenticado (tanto en sesiones web como en API JWT). Niveles de permiso estándar: - 'read': Permiso de lectura / consulta - 'read_write': Permiso de modificación y creación - 'admin': Permiso de control total """ def decorator(f): @wraps(f) def decorated_function(*args, **kwargs): user = None # Evaluar contexto JWT primero si está presente if hasattr(g, 'jwt_user') and g.jwt_user: user = g.jwt_user elif current_user and current_user.is_authenticated: user = current_user is_api = request.path.startswith('/api/') or request.is_json if not user: if is_api: return jsonify({'error': 'Unauthorized', 'message': 'Autenticación requerida.'}), 401 flash('Debe iniciar sesión para acceder a este recurso.', 'warning') return redirect(url_for('auth.login', next=request.url)) # Comprobar privilegios en la matriz RBAC if not user.has_permission(module, min_level): if is_api: return jsonify({ 'error': 'Forbidden', 'message': f'Permiso insuficiente en módulo "{module}". Nivel requerido: "{min_level}".' }), 403 flash(f'No posee permisos suficientes ({min_level}) para gestionar {module}.', 'danger') abort(403) return f(*args, **kwargs) return decorated_function return decorator