Skip to content

38. Anwendungsaufgabe: 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.

Zunächst fügen wir einen neuen Parameter in die Datei [configs/parameters] ein:


…        
         # CSRF-Token
        "with_csrftoken"False,
        # verwaltete Datenbanken: MySQL (MySQL), PostgreSQL (PostgreSQL)
        "databases"["mysql""pgres"],
        # Präfix der URL der Anwendung
        # Die Zeichenfolge leer lassen, wenn kein Präfix gewünscht ist, andernfalls /Präfix eingeben
        "prefix_url""/do",
        # Stamm-URL des Apache-Servers – die Zeichenfolge leer lassen, wenn die Ausführung außerhalb von Apache erfolgt
        "application_root""/impots"

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

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

Image



# Nun muss die Weiterleitungs-URL URL generiert werden, wobei das Token CSRF nicht vergessen werden darf, falls es angefordert wird
        if config['parameters']['with_csrftoken']:
            csrf_token = f"/{generate_csrf()}"
        else:
            csrf_token = ""

        # Weiterleitungsantwort
        return redirect(f"{config['parameters']['application_root']}{config['parameters']['prefix_url']}{ads['to']}{csrf_token}")
, status.HTTP_302_FOUND
  • Zeile 9: Wir haben das Stammverzeichnis der Anwendung am Anfang des Umleitungsziels URL hinzugefügt;

Außerdem müssen wir alle Fragmente korrigieren, damit die darin enthaltenen URL mit dem Stammverzeichnis der Anwendung (oder dem Alias WSGI) beginnen:

Image

Das Fragment [v-authentification]


<!-- Formular HTML – die Werte werden mit der Aktion [authentifier-utilisateur] übermittelt -->
<form method="post" action="{{modèle.application_root}}{{modèle.prefix_url}}/authentifier-utilisateur{{modèle.csrf_token}}"
>

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


</form>

Das Fragment [v-calcul-impot]


<!-- Formular HTML versendet -->
<form method="post" action="{{modèle.application_root}}{{modèle.prefix_url}}/calculer-impot{{modèle.csrf_token}}">
    <!-- Mitteilung in 12 Spalten auf blauem Hintergrund -->
    

</form>

Das Fragment [v-liste-simulations]




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


<!-- Simulationstabelle -->
<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 Fragment [v-menu]


<!-- Bootstrap-Menü -->
<nav class="nav flex-column">
    <!-- Anzeige einer Linkliste 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 oben genannten Fragmente verwenden alle die Vorlage [modèle.application_root]. Der Schlüssel [application_root] existiert derzeit nicht in den von den Vorlagenklassen generierten Vorlagen.

Image

Die Klasse [AbstractBaseModelForView], die die übergeordnete Klasse aller Klassen ist, die eine Vorlage generieren, sieht nun 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):
        # Berechnung des Tokens CSRF
        if config['parameters']['with_csrftoken']:
            csrf_token = f"/{generate_csrf()}"
        else:
            csrf_token = ""
        # Aktualisierung der als Parameter übergebenen Vorlage
        modèle.update({
            # CSRF-Token
            'csrf_token': csrf_token,
            # prefix_url
            'prefix_url': configQZXW2HTMLBWyJwYXJhbWV0ZXJzIl0ZQXQZXW2HTMLBWyJwcmVmaXhfdXJsIl0ZQX,
            # application_root
            'application_root': configQZXW2HTMLBWyJwYXJhbWV0ZXJzIl0ZQXQZXW2HTMLBWyJhcHBsaWNhdGlvbl9yb290Il0ZQX,
        })
  • Zeile 15: Die Methode [update_model] hat die Aufgabe, Ansichten in die Vorlage einzufügen:
    • Zeile 24: das Token CSRF;
    • Zeile 26: das Präfix von URL;
    • Zeile 28: das Stammverzeichnis der Anwendung oder der Alias WSGI;

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



        # Mögliche Aktionen aus der Ansicht heraus
        modèle['actions_possibles'] = ["afficher-vue-authentification""authentifier-utilisateur"]

        # Vervollständigung des Modells durch die übergeordnete Klasse
        super().update_model(modèle, config)

        # Das Modell wird zurückgegeben
        return modèle
  • Zeile 6: Jede untergeordnete Klasse ruft ihre übergeordnete Klasse auf, um das von ihr erstellte Modell zu aktualisieren;

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

Image

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


# Ordner des .wsgi-Skripts
define ROOT "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/impots/http-servers/13/apache"

# Name der durch diese Datei konfigurierten Website
# hier wird sie „flask-impots-withmysql“ heißen
# Die URL-Adressen lauten http(s)://flask-impots-withmysql/Pfad
define SITE "flask-impots-withmysql"

# Tragen Sie die Adresse IP 127.0.0.1 für die Website SITE in die Datei c:/windows/system32/drivers/etc/hosts ein

# Tragen Sie hier die Pfade zu den zu verwendenden Python-Bibliotheken ein – trennen Sie diese durch Kommas
# Hier die Bibliotheken einer virtuellen Python-Umgebung
WSGIPythonPath  "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages"

# Python-Home – nur erforderlich, wenn mehrere Python-Versionen installiert sind
# WSGIPythonHome „C:/Program Files/Python38“

# URL HTTP
<VirtualHost *:80>
    # mit dem Alias / haben die URL die Form /{prefixe_url}/action/...
    # mit dem Alias /impots haben die URL die Form /impots/{prefixe_url}/action/...
    #, wobei [prefixe_url] in parameters.py definiert ist
    WSGIScriptAlias /impots "${ROOT}/main_withmysql.wsgi"
    …
</VirtualHost>

# URL, gesichert mit HTTPS
<VirtualHost *:443>
    # mit dem Alias / werden die URL die Form /{prefixe_url}/action/... haben
    # mit dem Alias /impots haben die URL die Form /impots/{prefixe_url}/action/...
    #, wobei [prefixe_url] in parameters.py definiert ist
    WSGIScriptAlias /impots "${ROOT}/main_withmysql.wsgi"
    ..

</VirtualHost>
  • In Zeile 12 wird nun der Ordner [impots/http-servers/13/apache] verwendet.

Wir sind bereit für die Tests der auf Apache portierten Version 18. Die Konfiguration lautet wie folgt:

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

        # CSRF-Token
        "with_csrftoken"False,
        # Präfix der URL der Anwendung
        # Die Zeichenfolge leer lassen, wenn kein Präfix gewünscht ist, andernfalls /Präfix
        "prefix_url""/do",
        # Stamm-URL des Apache-Servers – die Zeichenfolge leer lassen, wenn die Ausführung außerhalb von Apache erfolgt
        "application_root""/impots"

Wir starten den Apache-Server sowie die beiden SGBD. Wir fragen die Seiten URL und [https://flask-impots-withmysql/impots/do] ab. Die Antwort des Servers lautet wie folgt:

Image

Wir erhalten nun tatsächlich die Anmeldeseite, die wir in der vorherigen Version nicht aufrufen konnten. Der Rest der Anwendung funktioniert normal.

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

Image

Die Begriffe „Alias“ (WSGI) und „Präfix“ (URL) haben dieselbe Funktion. Eines dieser beiden Konzepte ist überflüssig. Um also die URL des Apache-Servers mit der Zeichenfolge [/impots/do] zu präfixieren, gibt es 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

Es werden erneut die Konsolentests des Clients [http-clients/09] verwendet:

Image

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

In den Dateien [config] wird die Server-Einstellung URL wie folgt geändert:


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

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


…    
     # Request-/Response-Schritt
    def get_response(self, method: str, url_service: str, data_value: dict = None, json_value=None):
        # [method]: Methode HTTP, GET oder POST
        # [url_service]: URL als Dienst
        # [data]: Parameter des POST im Format „x-www-form-urlencoded“
        # [json]: Parameter von POST im JSON-Format
        # [cookies]: In die Anfrage einzufügende Cookies

        # Es muss eine Sitzung mit XML oder JSON vorliegen, andernfalls kann die Antwort nicht verarbeitet werden
        if self.__session_type not in ['json''xml']:
            raise ImpôtsError(73"il n'y a pas de session valide en cours")

        # Das Token CSRF wird zum Service-Token URL hinzugefügt
        if self.__csrf_token:
            url_service = f"{url_service}/{self.__csrf_token}"

        # Ausführung der Anfrage
        response = requests.request(method,
                                    url_service,
                                    data=data_value,
                                    json=json_value,
                                    cookies=self.__cookies,
                                    allow_redirects=True,
                                    # für das HTTPS-Protokoll
                                    verify=False)

        # Debug-Modus?
        if self.__debug:
            # Anmelder
            if not self.__logger:
                self.__logger = self.__config['logger']
            # man meldet sich an
            self.__logger.write(f"{response.text}\n")

        

        # das Ergebnis wird ausgegeben
        return résultat['réponse']
  • In Zeile 26 wird der Parameter [verify=False] hinzugefügt, da der Apache-Server das Protokoll HTTPS verwendet. Das Modul [requests] (Zeile 19) unterstützt das Protokoll HTTPS nativ. Standardmäßig überprüft es die Gültigkeit des Sicherheitszertifikats, das ihm der Server HTTPS übermittelt, 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] gibt dann lediglich eine Warnung (warning) auf der Konsole aus.

Nach diesen Änderungen sollten alle Konsolentests funktionieren.