Skip to content

38. Ejercicio de aplicación: version 18

38.1. Implementación

Image

El archivo [impots/http-servers/13] se obtiene inicialmente copiando el archivo [impots/http-servers/12] y, a continuación, se modifica parcialmente.

Comenzamos añadiendo un nuevo parámetro en el archivo [configs/parameters]:


…        
        # token csrf
        "with_csrftoken"False,
        # bases gestionadas MySQL (mysql), PostgreSQL (pgres)
        "databases"["mysql""pgres"],
        # prefijo de los URL de la aplicación
        # establecer la cadena como vacía si no se desea ningún prefijo o /prefijo en caso contrario
        "prefix_url""/do",
        # url raíz del servidor Apache: dejar la cadena vacía para una ejecución fuera de Apache
        "application_root""/impots"

En la línea 10, el parámetro [application_root] representará el alias WSGI del servidor virtual Apache.

Con este parámetro, podemos corregir la instrucción de [responses/HtmlResponse] que había provocado el error:

Image



# ahora hay que generar el URL de redireccionamiento sin olvidar el token CSRF si se solicita
        if config['parameters']['with_csrftoken']:
            csrf_token = f"/{generate_csrf()}"
        else:
            csrf_token = ""

        # respuesta de redireccionamiento
        return redirect(f"{config['parameters']['application_root']}{config['parameters']['prefix_url']}{ads['to']}{csrf_token}")
, status.HTTP_302_FOUND
  • línea 9: hemos añadido la raíz de la aplicación al principio del destino de redireccionamiento URL;

También debemos corregir todos los fragmentos para que los URL que contienen comiencen por la raíz de la aplicación (o alias WSGI):

Image

El fragmento [v-authentification]


<!-- formulario HTML: se envían sus valores con la acción [authentifier-utilisateur] -->
<form method="post" action="{{modèle.application_root}}{{modèle.prefix_url}}/authentifier-utilisateur{{modèle.csrf_token}}"
>

    <!-- título -->
    <div class="alert alert-primary" role="alert">
        <h4>Veuillez vous authentifier</h4>
    </div>


</form>

El fragmento [v-calcul-impot]


<!-- formulario HTML enviado -->
<form method="post" action="{{modèle.application_root}}{{modèle.prefix_url}}/calculer-impot{{modèle.csrf_token}}">
    <!-- mensaje en 12 columnas sobre fondo azul -->
    

</form>

El fragmento [v-liste-simulations]




{% if modèle.simulations is defined and modèle.simulations|length!=0 %}


<!-- tabla de simulaciones -->
<table class="table table-sm table-hover table-striped">
    
    <tr>
        <th scope="row">{{simulation.id}}</th>
        <td>{{simulation.marié}}</td>
        <td>{{simulation.enfants}}</td>
        <td>{{simulation.salaire}}</td>
        <td>{{simulation.impôt}}</td>
        <td>{{simulation.surcôte}}</td>
        <td>{{simulation.décôte}}</td>
        <td>{{simulation.réduction}}</td>
        <td>{{simulation.taux}}</td>
        <td><a href="{{modèle.application_root}}{{modèle.prefix_url}}/supprimer-simulation/{{simulation.id}}{{modèle.csrf_token}}">Supprimer</a></td>
    </tr>
    {% endfor %}
    </tr>
    </tbody>
</table>
{% endif %}

El fragmento [v-menu]


<!-- menú Bootstrap -->
<nav class="nav flex-column">
    <!-- visualización de una lista de enlaces HTML -->
    {% for optionMenu in modèle.optionsMenu %}
    <a class="nav-link" href="{{modèle.application_root}}{{modèle.prefix_url}}{{optionMenu.url}}{{modèle.csrf_token}}">{{optionMenu.text}}</a>
    {% endfor %}
</nav>

Todos los fragmentos anteriores utilizan la plantilla [modèle.application_root]. Por el momento, la clave [application_root] no existe en las plantillas generadas por las clases de plantillas.

Image

La clase [AbstractBaseModelForView], que es la clase principal de todas las clases que generan una plantilla, queda de la siguiente manera:


from abc import abstractmethod

from flask import Request
from flask_wtf.csrf import generate_csrf
from werkzeug.local import LocalProxy

from InterfaceModelForView import InterfaceModelForView

class AbstractBaseModelForView(InterfaceModelForView):

    @abstractmethod
    def get_model_for_view(self, request: Request, session: LocalProxy, config: dict, résultat: dict) -> dict:
        pass

    def update_model(self, modèle: dict, config: dict):
        # cálculo del token CSRF
        if config['parameters']['with_csrftoken']:
            csrf_token = f"/{generate_csrf()}"
        else:
            csrf_token = ""
        # actualización de la plantilla pasada como parámetro
        modèle.update({
            # token csrf
            'csrf_token': csrf_token,
            # prefix_url
            'prefix_url': config["parameters"]["prefix_url"],
            # application_root
            'application_root': config["parameters"]["application_root"],
        })
  • línea 15: el método [update_model] tiene la función de insertar vistas en la plantilla:
    • línea 24: el token CSRF;
    • línea 26: el prefijo de URL;
    • línea 28: la raíz de la aplicación o alias WSGI;

Las cuatro clases hijas llaman a la clase padre con el siguiente código:



        # actions possibles à partir de la vue
        modèle['actions_possibles'] = ["afficher-vue-authentification""authentifier-utilisateur"]

        # finition du modèle par la classe parent
        super().update_model(modèle, config)

        # on rend le modèle
        return modèle
  • línea 6: cada clase hija llama a su clase padre para actualizar el modelo que ha creado;

La version 18 está lista. Retomamos los dos servidores virtuales de Apache de la version 17 y los modificamos:

Image

Los dos archivos [flask-impots-withXX.conf] solo se modifican en un punto:


# dossier du script .wsgi
define ROOT "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/impots/http-servers/13/apache"

# nom du site web configuré par ce fichier
# ici il s'appellera flask-impots-withmysql
# les URL seront du type http(s)://flask-impots-withmysql/ruta
define SITE "flask-impots-withmysql"

# mettre l'adresse IP 127.0.0.1 pour site SITE dans c:/windows/system32/drivers/etc/hosts

# mettre ici les chemins des bibliothèques Python à utiliser - les séparer par des virgules
# ici les bibliothèques d'un environnement virtuel Python
WSGIPythonPath  "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages"

# Python Home - nécessaire uniquement s'il y a plusieurs versions de Python installées
# WSGIPythonHome "C:/Program Files/Python38"

# URL HTTP
<VirtualHost *:80>
    # avec l'alias / les URL auront la forme /{prefixe_url}/action/...
    # avec l'alias /impots les URL auront la forme /impots/{prefixe_url}/action/...
    # où [prefixe_url] est défini dans parameters.py
    WSGIScriptAlias /impots "${ROOT}/main_withmysql.wsgi"
    …
</VirtualHost>

# URL sécurisées avec HTTPS
<VirtualHost *:443>
    # avec l'alias / les URL auront la forme /{prefixe_url}/action/...
    # avec l'alias /impots les URL auront la forme /impots/{prefixe_url}/action/...
    # où [prefixe_url] est défini dans parameters.py
    WSGIScriptAlias /impots "${ROOT}/main_withmysql.wsgi"
    ..

</VirtualHost>
  • línea 12, ahora utilizamos la carpeta [impots/http-servers/13/apache].

Estamos listos para las pruebas de version 18 en Apache. La configuración es la siguiente:

  • el alias WSGI es /impots en los dos archivos de configuración de los servidores virtuales;
  • en el archivo de configuración [configs/parameters], los parámetros son los siguientes:

        # token csrf
        "with_csrftoken"False,
        # prefijo de los URL de la aplicación
        # establecer la cadena como vacía si no se desea ningún prefijo o /prefijo en caso contrario
        "prefix_url""/do",
        # url raíz del servidor Apache: dejar la cadena vacía para una ejecución fuera de Apache
        "application_root""/impots"

Se inician el servidor Apache y los dos SGBD. Se solicita el URL [https://flask-impots-withmysql/impots/do]. La respuesta del servidor es la siguiente:

Image

Se obtiene correctamente la pantalla de autenticación que no se había podido obtener en el version anterior. El resto de la aplicación funciona con normalidad.

Ahora probamos el otro servidor virtual. Solicitamos el URL [https://flask-impots-withpgres/impots/do]. La respuesta del servidor es la siguiente:

Image

Los conceptos de alias WSGI y prefijo de URL desempeñan la misma función. Uno de estos dos conceptos es redundante. Así, para anteponer la cadena [/impots/do] a los URL del servidor Apache, se puede proceder de tres maneras:

1 – [WGSIAlias /impots] y [prefix_url=’/do’];

2 - [WGSIAlias /] y [prefix_url=’/impots/do’];

3 – [WGSIAlias /impots/do] y [prefix_url=’’];

38.2. Pruebas de consola

Se vuelven a utilizar las pruebas de consola del cliente [http-clients/09]:

Image

  • el URL del servidor debe modificarse en las configuraciones [1] y [3];
  • hay que realizar una modificación en la capa [dao] para que sea compatible con el protocolo HTTPS del servidor Apache;

En los archivos [config], el URL del servidor queda como sigue:


        "server": {
            # "urlServer": "http://127.0.0.1:5000",
            # "urlServer": "http://127.0.0.1:5000/do",
            "urlServer""https://flask-impots-withmysql/impots/do",
            "user": {
                "login""admin",
                "password""admin"
            },
            "url_services": {
                
            }
        },
        # modo debug
        "debug"True,
        # csrf_token
        "with_csrftoken"False,
  • línea 4: el nuevo URL del servidor. Por primera vez en este documento, el cliente utiliza el protocolo HTTPS;

La clase [ImpôtsDaoWihHttpSession] de la capa [dao] evoluciona de la siguiente manera:


…    
    # etapa de solicitud/respuesta
    def get_response(self, method: str, url_service: str, data_value: dict = None, json_value=None):
        # [method]: método HTTP GET o POST
        # [url_service]: URL de servicio
        # [data]: parámetros del POST en x-www-form-urlencoded
        # [json]: parámetros de POST en json
        # [cookies]: cookies que se deben incluir en la solicitud

        #: debe haber una sesión XML o JSON; de lo contrario, no se podrá gestionar la respuesta
        if self.__session_type not in ['json''xml']:
            raise ImpôtsError(73"il n'y a pas de session valide en cours")

        # se añade el token CSRF al URL de servicio
        if self.__csrf_token:
            url_service = f"{url_service}/{self.__csrf_token}"

        # ejecución de la solicitud
        response = requests.request(method,
                                    url_service,
                                    data=data_value,
                                    json=json_value,
                                    cookies=self.__cookies,
                                    allow_redirects=True,
                                    # para el protocolo https
                                    verify=False)

        # modo debug ?
        if self.__debug:
            # registrador
            if not self.__logger:
                self.__logger = self.__config['logger']
            # se registra
            self.__logger.write(f"{response.text}\n")

        

        # se muestra el resultado
        return résultat['réponse']
  • en la línea 26, se añade el parámetro [verify=False] debido al protocolo HTTPS utilizado por el servidor Apache. El módulo [requests] (línea 19) es capaz de gestionar de forma nativa el protocolo HTTPS. Por defecto, comprueba la validez del certificado de seguridad que le envía el servidor HTTPS y lanza una excepción si el certificado recibido no es válido. Este es el caso aquí, donde el servidor Apache de Laragon envía un certificado autofirmado. Para evitar la excepción, se utiliza el parámetro [verify=False] para indicar al módulo [requests] que no lance una excepción. [requests] se limita entonces a mostrar una advertencia (warning) en la consola.

Una vez realizadas estas modificaciones, todas las pruebas de consola deberían funcionar.