Skip to content

38. Praktische Übung: Version 18

38.1. Implementierung

Image

Der Ordner [impots/http-servers/13] wird zunächst durch Kopieren des Ordners [impots/http-servers/12] erstellt und anschließend teilweise geändert.

Wir beginnen damit, der Datei [configs/parameters] einen neuen Parameter hinzuzufügen:


…        
        # token csrf
        "with_csrftoken"False,
        # bases gérées MySQL (mysql), PostgreSQL (pgres)
        "databases"["mysql""pgres"],
        # préfixe des URL de l'application
        # mettre la chaîne vide si on ne veut pas de préfixe ou /préfixe sinon
        "prefix_url""/do",
        # url racine du serveur Apache - mettre la chaîne vide pour une exécution en-dehors d'Apache
        "application_root""/impots"

Zeile 10: Der Parameter [application_root] steht für den WSGI-Alias des virtuellen Apache-Servers.

Mit diesem Parameter können wir die Anweisung [responses/HtmlResponse] korrigieren, die den Fehler verursacht hat:

Image



# now it's time to generate the URL redirection, not forgetting the CSRF token if requested
        if config['parameters']['with_csrftoken']:
            csrf_token = f"/{generate_csrf()}"
        else:
            csrf_token = ""
 
        # redirect response
        return redirect(f"{config['parameters']['application_root']}{config['parameters']['prefix_url']}{ads['to']}{csrf_token}")
, status.HTTP_302_FOUND
  • Zeile 9: Wir haben den Anwendungsstamm an den Anfang der URL des Umleitungsziels angefügt;

Außerdem müssen wir alle Fragmente so korrigieren, dass die darin enthaltenen URLs mit dem Anwendungsstamm (oder dem WSGI-Alias) beginnen:

Image

Das Fragment [v-authentication]


<!-- form HTML - post its values with the [authenticate-user] action -->
<form method="post" action="{{modèle.application_root}}{{modèle.prefix_url}}/authentifier-utilisateur{{modèle.csrf_token}}"
>
 
    <!-- title -->
    <div class="alert alert-primary" role="alert">
        <h4>Veuillez vous authentifier</h4>
    </div>

 
</form>

Das [v-calcul-impot]-Fragment


<!-- form HTML posted -->
<form method="post" action="{{modèle.application_root}}{{modèle.prefix_url}}/calculer-impot{{modèle.csrf_token}}">
    <!-- 12-column message on blue background -->
    
 
</form>

Das [v-liste-simulations]-Fragment



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

 
<!-- simulation table -->
<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 %}

Das [v-menu]-Fragment


<!-- bootstrap menu -->
<nav class="nav flex-column">
    <!-- display a list of links 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>

Die obigen Fragmente verwenden alle das Modell [model.application_root]. Derzeit existiert der Schlüssel [application_root] nicht in den von den Modellklassen generierten Modellen.

Image

Die Klasse [AbstractBaseModelForView], die die Oberklasse aller Klassen ist, die eine Vorlage generieren, sieht wie folgt aus:

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):
        #  token calculation CSRF
        if config['parameters']['with_csrftoken']:
            csrf_token = f"/{generate_csrf()}"
        else:
            csrf_token = ""
        #  update the model passed in parameter
        modèle.update({
            #  csrf token
            'csrf_token': csrf_token,
            #  prefix_url
            'prefix_url': config["parameters"]["prefix_url"],
            #  application_root
            'application_root': config["parameters"]["application_root"],
        })
  • Zeile 15: Die Methode [update_model] ist dafür zuständig, Folgendes zur View-Vorlage hinzuzufügen:
    • Zeile 24: das CSRF-Token;
    • Zeile 26: das URL-Präfix;
    • Zeile 28: das Anwendungsstammverzeichnis oder den WSGI-Alias;

Die vier untergeordneten Klassen rufen die übergeordnete Klasse mit dem folgenden Code auf:



        # 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
  • Zeile 6: Jede Unterklasse ruft ihre Oberklasse auf, um das von ihr erstellte Modell zu aktualisieren;

Version 18 ist fertig. Wir verwenden die beiden virtuellen Apache-Server aus Version 17 wieder und passen sie an:

Image

Die beiden [flask-imports-withXX.conf]-Dateien werden an nur einer Stelle geändert:


# 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/path
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>
  • Zeile 12: Wir verwenden nun das Verzeichnis [taxes/http-servers/13/apache].

Wir sind bereit, Version 18 unter Apache zu testen. Die Konfiguration lautet wie folgt:

  • Der WSGI-Alias lautet in beiden Konfigurationsdateien für virtuelle Server /impots;
  • in der Konfigurationsdatei [configs/parameters] lauten die Parameter wie folgt:

        # token csrf
        "with_csrftoken"False,
        # préfixe des URL de l'application
        # mettre la chaîne vide si on ne veut pas de préfixe ou /préfixe sinon
        "prefix_url""/do",
        # url racine du serveur Apache - mettre la chaîne vide pour une exécution en-dehors d'Apache
        "application_root""/impots"

Wir starten den Apache-Server und die beiden DBMS. Wir rufen die URL [https://flask-impots-withmysql/impots/do] auf. Die Antwort des Servers lautet wie folgt:

Image

Wir sehen nun die Anmeldeseite, auf die wir in der vorherigen Version nicht zugreifen konnten. Der Rest der Anwendung funktioniert einwandfrei.

Nun testen wir den anderen virtuellen Server. Wir rufen die URL [https://flask-impots-withpgres/impots/do] auf. Die Antwort des Servers lautet wie folgt:

Image

Die Konzepte von WSGI-Aliasen und URL-Präfixen dienen demselben Zweck. Eines dieser beiden Konzepte ist überflüssig. Um Apache-Server-URLs mit der Zeichenfolge [/impots/do] zu versehen, gibt es also drei Möglichkeiten:

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

2 – [WGSIAlias /] und [prefix_url=’/impots/do’];

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

38.2. Konsolentests

Wir verwenden erneut die Client-Konsolentests [http-clients/09]:

Image

  • Die Server-URL muss in den Konfigurationen [1] und [3] geändert werden;
  • es muss eine Änderung an der [dao]-Schicht vorgenommen werden, damit diese das HTTPS-Protokoll des Apache-Servers unterstützt;

In den [config]-Dateien lautet die Server-URL nun wie folgt:


        "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": {
                
            }
        },
        # mode debug
        "debug"True,
        # csrf_token
        "with_csrftoken"False,
  • Zeile 4: die neue Server-URL. Zum ersten Mal in diesem Dokument verwendet der Client das HTTPS-Protokoll;

Die Klasse [ImpôtsDaoWihHttpSession] in der [dao]-Schicht entwickelt sich wie folgt:

…    
    # étape request / response
    def get_response(self, method: str, url_service: str, data_value: dict = None, json_value=None):
        #  [method]: HTTP GET or POST method
        #  [url_service] : URL of service
        #  [data]: POST parameters in x-www-form-urlencoded
        #  [json]: POST parameters in json
        #  [cookies]: cookies to include in the request

        #  you must have a XML or JSON session, otherwise you won't be able to handle the response
        if self.__session_type not in ['json', 'xml']:
            raise ImpôtsError(73, "il n'y a pas de session valide en cours")

        #  we add the CSRF token to the URL service token
        if self.__csrf_token:
            url_service = f"{url_service}/{self.__csrf_token}"

        #  query execution
        response = requests.request(method,
                                    url_service,
                                    data=data_value,
                                    json=json_value,
                                    cookies=self.__cookies,
                                    allow_redirects=True,
                                    #  for the https protocol
                                    verify=False)

        #  debug mode?
        if self.__debug:
            #  logger
            if not self.__logger:
                self.__logger = self.__config['logger']
            #  log on
            self.__logger.write(f"{response.text}\n")

        …

        #  we return the result
        return résultat['réponse']
  • In Zeile 26 fügen wir den Parameter [verify=False] hinzu, da der Apache-Server das HTTPS-Protokoll verwendet. Das Modul [requests] (Zeile 19) unterstützt das HTTPS-Protokoll nativ. Standardmäßig überprüft es die Gültigkeit des vom HTTPS-Server gesendeten Sicherheitszertifikats und löst eine Ausnahme aus, wenn das empfangene Zertifikat ungültig ist. Dies ist hier der Fall, da der Apache-Server von Laragon ein selbstsigniertes Zertifikat sendet. Um die Ausnahme zu vermeiden, verwenden wir den Parameter [verify=False], um dem Modul [requests] mitzuteilen, keine Ausnahme auszulösen. [requests] zeigt dann lediglich eine Warnung auf der Konsole an.

Nach diesen Änderungen sollten alle Konsolentests funktionieren.