Heim Backend-Entwicklung Python-Tutorial Verwendung des Flask-Framework-Formular-Plug-ins Flask-WTF von Python zur Implementierung der Web-Login-Überprüfung

Verwendung des Flask-Framework-Formular-Plug-ins Flask-WTF von Python zur Implementierung der Web-Login-Überprüfung

Aug 04, 2016 am 08:55 AM
flask flask-wtf python 表单

Formulare sind das grundlegende Element, das Benutzern die Interaktion mit unseren Webanwendungen ermöglicht. Flask selbst hilft uns nicht bei Formularen, aber die Flask-WTF-Erweiterung ermöglicht uns die Verwendung des beliebten WTForms-Pakets in unseren Flask-Anwendungen. Dieses Paket erleichtert die Definition von Formularen und die Bearbeitung von Übermittlungen.

Flasche-WTF
Das erste, was wir mit Flask-WTF machen wollen (nach der Installation, GitHub-Projektseite: https://github.com/lepture/flask-wtf), ist die Definition eines Formulars im myapp.forms-Paket.

# ourapp/forms.py

from flask_wtf import Form
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Email

class EmailPasswordForm(Form):
 email = StringField('Email', validators=[DataRequired(), Email()])
 password = PasswordField('Password', validators=[DataRequired()])

Nach dem Login kopieren
Nach dem Login kopieren

Vor Flask-WTF Version 0.9 stellte Flask-WTF eine eigene Verpackung für WTForms-Felder und Validatoren bereit. Möglicherweise sehen Sie draußen viel Code, der TextField und PasswordField aus flask.ext.wtforms und nicht aus wtforms importiert.
Nach Flask-WTF Version 0.9 sollten wir diese Felder und Validatoren direkt aus wtforms importieren.
Das von uns definierte Formular ist ein Benutzeranmeldeformular. Wir nennen es EmailPasswordForm() und können dieselbe Formularklasse (Form) für andere Dinge wie Registrierungsformulare wiederverwenden. Hier definieren wir kein langes und nutzloses Formular, sondern wählen ein sehr häufig verwendetes Formular aus, nur um Ihnen vorzustellen, wie Sie Flask-WTF zum Definieren eines Formulars verwenden. Vielleicht wird in Zukunft in einem formalen Projekt eine besonders komplexe Form definiert. Für Formulare, die Feldnamen enthalten, empfehlen wir die Verwendung eines Namens, der innerhalb eines Formulars eindeutig und eindeutig ist. Es muss gesagt werden, dass wir für eine Langform möglicherweise einen Feldnamen vergeben müssen, der besser mit dem oben Gesagten übereinstimmt.

Anmeldeformulare können einiges für uns tun. Es schützt unsere Anwendung vor CSRF-Schwachstellen, validiert Benutzereingaben und rendert geeignete Markups für die Felder, die wir für unsere Formulare definieren.

CSRF-Schutz und -Verifizierung
CSRF steht für Cross-Site Request Forgery. Ein CSRF-Angriff liegt vor, wenn ein Dritter eine Anfrage (z. B. eine Formularübermittlung) an den Server einer Anwendung fälscht. Ein anfälliger Server geht davon aus, dass die Daten eines Formulars von seiner eigenen Website stammen und handelt entsprechend.

Angenommen, ein E-Mail-Anbieter ermöglicht Ihnen die Löschung Ihres Kontos durch Absenden eines Formulars. Das Formular sendet eine POST-Anfrage an den Endpunkt „account_delete“ auf dem Server und löscht das angemeldete Konto, wenn das Formular gesendet wird. Wir können auf unserer Website ein Formular erstellen, das eine POST-Anfrage an denselben Account_delete-Endpunkt sendet. Wenn wir nun zulassen, dass jemand auf unserem Formular auf die Schaltfläche „Senden“ klickt (oder dies über JavaScript tut), wird der vom E-Mail-Anbieter bereitgestellte Login entfernt. Natürlich weiß der E-Mail-Anbieter noch nicht, dass die Formularübermittlung nicht auf seiner Website erfolgt.

Wie kann ich also verhindern, dass POST-Anfragen von anderen Websites kommen? WTForms macht dies möglich, indem beim Rendern jedes Formulars ein eindeutiger Token generiert wird. Das generierte Token wird zusammen mit den Daten in der POST-Anfrage an den Server zurückgesendet und das Token muss vom Server validiert werden, bevor das Formular akzeptiert werden kann. Entscheidend ist, dass das Token mit einem in der Sitzung des Benutzers gespeicherten Wert (Cookies) verknüpft ist und nach einer bestimmten Zeitspanne abläuft (Standard sind 30 Minuten). Auf diese Weise stellen Sie sicher, dass die Person, die ein gültiges Formular einreicht, dieselbe Person ist, die die Seite geladen hat (oder zumindest dieselbe Person, die denselben Computer verwendet), und dass dies nur innerhalb von 30 Minuten nach dem Laden der Seite möglich ist.

Um CSRF mit Flask-WTF zu schützen, müssen wir eine Ansicht für unsere Anmeldeseite definieren.

# ourapp/views.py

from flask import render_template, redirect, url_for

from . import app
from .forms import EmailPasswordForm

@app.route('/login', methods=["GET", "POST"])
def login():
 form = EmailPasswordForm()
 if form.validate_on_submit():

  # Check the password and log the user in
  # [...]

  return redirect(url_for('index'))
 return render_template('login.html', form=form)

Nach dem Login kopieren

Wenn das Formular übermittelt und verifiziert wurde, können wir mit der Login-Logik fortfahren. Wenn es nicht übermittelt wurde (z. B. nur eine GET-Anfrage), müssen wir das Formularobjekt an unsere Vorlage übergeben, damit es gerendert werden kann. So sieht die Vorlage aus, wenn wir den CSRF-Schutz verwenden.

{# ourapp/templates/login.html #}

{% extends "layout.html" %}
{% endraw %}
<html>
 <head>
  <title>Login Page</title>
 </head>
 <body>
  <form action="{{ url_for('login') }}" method="post">
   <input type="text" name="email" />
   <input type="password" name="password" />
   {{ form.csrf_token }}
  </form>
 </body>
</html>

Nach dem Login kopieren

{% raw %}{{ form.csrf_token }}{% endraw %} rendert ein verstecktes Feld, das diese ausgefallenen CSRF-Tokens enthält und nach dem gesucht wird, wenn WTForms das Formular validiert. Wir müssen uns nicht darum kümmern, die Logik zur Handhabung des Tokens einzubauen, WTForms erledigt das proaktiv für uns. Hurra!

Benutzerdefinierte Verifizierung
Zusätzlich zu den von WTForms bereitgestellten integrierten Formularvalidatoren (z. B. Required(), Email() usw.) können wir unsere eigenen Validatoren erstellen. Wir veranschaulichen, wie Sie Ihren eigenen Validator erstellen, indem Sie einen Unique()-Validator schreiben, der die Datenbank überprüft und sicherstellt, dass der vom Benutzer bereitgestellte Wert nicht in der Datenbank vorhanden ist. Dadurch kann sichergestellt werden, dass der Benutzername oder die E-Mail-Adresse nicht bereits verwendet werden. Ohne WTForms müssten wir diese Dinge möglicherweise in der Ansicht tun, aber jetzt können wir Dinge im Formular selbst tun.

Lassen Sie uns nun ein einfaches Registrierungsformular definieren. Tatsächlich ist dieses Formular fast dasselbe wie das Anmeldeformular. Wir werden später einfach einige benutzerdefinierte Validatoren hinzufügen.

# ourapp/forms.py

from flask_wtf import Form
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Email

class EmailPasswordForm(Form):
 email = StringField('Email', validators=[DataRequired(), Email()])
 password = PasswordField('Password', validators=[DataRequired()])

Nach dem Login kopieren
Nach dem Login kopieren

现在我们要添加我们的验证器用来确保它们提供的邮箱地址不存在数据库中。我们把这个验证器放在一个新的 util 模块,util.validators。

# ourapp/util/validators.py
from wtforms.validators import ValidationError

class Unique(object):
 def __init__(self, model, field, message=u'This element already exists.'):
  self.model = model
  self.field = field

 def __call__(self, form, field):
  check = self.model.query.filter(self.field == field.data).first()
  if check:
   raise ValidationError(self.message)

Nach dem Login kopieren

这个验证器假设我们是使用 SQLAlchemy 来定义我们的模型。WTForms 期待验证器返回某种可调用的对象(例如,一个可调用的类)。

在 Unique() 的 \_\_init\_\_ 中我们可以指定哪些参数传入到验证器中,在本例中我们要传入相关的模型(例如,在我们例子中是传入 User 模型)以及要检查的字段。当验证器被调用的时候,如果定义模型的任何实例匹配表单中提交的值,它将会抛出一个 ValidationError。我们也可以添加一个具有通用默认值的消息,它将会被包含在 ValidationError 中。

现在我们可以修改 EmailPasswordForm,使用我们自定义的 Unique 验证器。

# ourapp/forms.py

from flask_wtf import Form
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired

from .util.validators import Unique
from .models import User

class EmailPasswordForm(Form):
 email = StringField('Email', validators=[DataRequired(), Email(),
  Unique(
   User,
   User.email,
   message='There is already an account with that email.')])
 password = PasswordField('Password', validators=[DataRequired()])

Nach dem Login kopieren

渲染表单
WTForms 也能帮助我们为表单渲染成 HTML 表示。WTForms 实现的 Field 字段能够渲染成该字段的 HTML 表示,所以为了渲染它们,我们只必须在我们模板中调用表单的字段。这就像渲染 csrf_token 字段。下面给出了一个登录模板的示例,在里面我们使用 WTForms 来渲染我们的字段。

{# ourapp/templates/login.html #}

{% extends "layout.html" %}
<html>
 <head>
  <title>Login Page</title>
 </head>
 <body>
  <form action="" method="post">
   {{ form.email }}
   {{ form.password }}
   {{ form.csrf_token }}
  </form>
 </body>
</html>

Nach dem Login kopieren

我们可以自定义如何渲染字段,通过传入字段的属性作为参数到调用中。

<form action="" method="post">
 {{ form.email.label }}: {{ form.email(placeholder='yourname@email.com') }}
 <br>
 {% raw %}{{ form.password.label }}: {{ form.password }}{% endraw %}
 <br>
 {% raw %}{{ form.csrf_token }}{% endraw %}
</form>
Nach dem Login kopieren

处理 OpenID 登录
现实生活中,我们发现有很多人都不知道他们拥有一些公共账号。一部分大牌的网站或服务商都会为他们的会员提供公共账号的认证。举个栗子,如果你有一个 google 账号,其实你就有了一个公共账号,类似的还有 Yahoo, AOL, Flickr 等。
为了方便我们的用户能简单的使用他们的公共账号,我们将把这些公共账号的链接添加到一个列表,这样用户就不用自手工输入了。

我们要把一些提供给用户的公共账号服务商定义到一个列表里面,这个列表就放到配置文件中吧 (fileconfig.py):

CSRF_ENABLED = True
SECRET_KEY = 'you-will-never-guess'
 
OPENID_PROVIDERS = [
 { 'name': 'Google', 'url': 'https://www.google.com/accounts/o8/id' },
 { 'name': 'Yahoo', 'url': 'https://me.yahoo.com' },
 { 'name': 'AOL', 'url': 'http://openid.aol.com/<username>' },
 { 'name': 'Flickr', 'url': 'http://www.flickr.com/<username>' },
 { 'name': 'MyOpenID', 'url': 'https://www.myopenid.com' }]
Nach dem Login kopieren

接下来就是要在我们的登录视图函数中使用这个列表了:

@app.route('/login', methods = ['GET', 'POST'])
def login():
 form = LoginForm()
 if form.validate_on_submit():
  flash('Login requested for OpenID="' + form.openid.data + '", remember_me=' + str(form.remember_me.data))
  return redirect('/index')
 return render_template('login.html',
  title = 'Sign In',
  form = form,
  providers = app.config['OPENID_PROVIDERS'])
Nach dem Login kopieren

我们从 app.config 中引入了公共账号服务商的配置列表,然后把它作为一个参数通过 render_template 函数引入到模板。

接下来要做的我想你也猜得到,我们需要在登录模板中把这些服务商链接显示出来。

<!-- extend base layout -->
{% extends "base.html" %}
 
{% block content %}
<script type="text/javascript">
function set_openid(openid, pr)
{
 u = openid.search('<username>')
 if (u != -1) {
  // openid requires username
  user = prompt('Enter your ' + pr + ' username:')
  openid = openid.substr(0, u) + user
 }
 form = document.forms['login'];
 form.elements['openid'].value = openid
}
</script>
<h1>Sign In</h1>
<form action="" method="post" name="login">
 {{form.hidden_tag()}}
 <p>
  Please enter your OpenID, or select one of the providers below:<br>
  {{form.openid(size=80)}}
  {% for error in form.errors.openid %}
  <span style="color: red;">[{{error}}]</span>
  {% endfor %}<br>
  |{% for pr in providers %}
  <a href="javascript:set_openid('{{pr.url}}', '{{pr.name}}');">{{pr.name}}</a> |
  {% endfor %}
 </p>
 <p>{{form.remember_me}} Remember Me</p>
 <p><input type="submit" value="Sign In"></p>
</form>
{% endblock %}
Nach dem Login kopieren

这次的模板添加的东西似乎有点多。一些公共账号需要提供用户名,为了解决这个我们用了点 javascript。当用户点击相关的公共账号链接时,需要用户名的公共账号会提示用户输入用户名, javascript 会把用户名处理成可用的公共账号,最后再插入到 openid 字段的文本框中。

下面这个是在登录页面点击 google 链接后显示的截图:

2016712172533772.jpg (450×300)

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Wie man alles in Myrise freischaltet
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Muss MySQL bezahlen? Muss MySQL bezahlen? Apr 08, 2025 pm 05:36 PM

MySQL hat eine kostenlose Community -Version und eine kostenpflichtige Enterprise -Version. Die Community -Version kann kostenlos verwendet und geändert werden, die Unterstützung ist jedoch begrenzt und für Anwendungen mit geringen Stabilitätsanforderungen und starken technischen Funktionen geeignet. Die Enterprise Edition bietet umfassende kommerzielle Unterstützung für Anwendungen, die eine stabile, zuverlässige Hochleistungsdatenbank erfordern und bereit sind, Unterstützung zu bezahlen. Zu den Faktoren, die bei der Auswahl einer Version berücksichtigt werden, gehören Kritikalität, Budgetierung und technische Fähigkeiten von Anwendungen. Es gibt keine perfekte Option, nur die am besten geeignete Option, und Sie müssen die spezifische Situation sorgfältig auswählen.

So verwenden Sie MySQL nach der Installation So verwenden Sie MySQL nach der Installation Apr 08, 2025 am 11:48 AM

Der Artikel führt den Betrieb der MySQL -Datenbank vor. Zunächst müssen Sie einen MySQL -Client wie MySQLworkBench oder Befehlszeilen -Client installieren. 1. Verwenden Sie den Befehl mySQL-uroot-P, um eine Verbindung zum Server herzustellen und sich mit dem Stammkonto-Passwort anzumelden. 2. Verwenden Sie die Erstellung von Createdatabase, um eine Datenbank zu erstellen, und verwenden Sie eine Datenbank aus. 3.. Verwenden Sie CreateTable, um eine Tabelle zu erstellen, Felder und Datentypen zu definieren. 4. Verwenden Sie InsertInto, um Daten einzulegen, Daten abzufragen, Daten nach Aktualisierung zu aktualisieren und Daten nach Löschen zu löschen. Nur indem Sie diese Schritte beherrschen, lernen, mit gemeinsamen Problemen umzugehen und die Datenbankleistung zu optimieren, können Sie MySQL effizient verwenden.

MySQL kann nach dem Herunterladen nicht installiert werden MySQL kann nach dem Herunterladen nicht installiert werden Apr 08, 2025 am 11:24 AM

Die Hauptgründe für den Fehler bei MySQL -Installationsfehlern sind: 1. Erlaubnisprobleme, Sie müssen als Administrator ausgeführt oder den Sudo -Befehl verwenden. 2. Die Abhängigkeiten fehlen, und Sie müssen relevante Entwicklungspakete installieren. 3. Portkonflikte müssen Sie das Programm schließen, das Port 3306 einnimmt, oder die Konfigurationsdatei ändern. 4. Das Installationspaket ist beschädigt. Sie müssen die Integrität herunterladen und überprüfen. 5. Die Umgebungsvariable ist falsch konfiguriert und die Umgebungsvariablen müssen korrekt entsprechend dem Betriebssystem konfiguriert werden. Lösen Sie diese Probleme und überprüfen Sie jeden Schritt sorgfältig, um MySQL erfolgreich zu installieren.

Die MySQL -Download -Datei ist beschädigt und kann nicht installiert werden. Reparaturlösung Die MySQL -Download -Datei ist beschädigt und kann nicht installiert werden. Reparaturlösung Apr 08, 2025 am 11:21 AM

Die MySQL -Download -Datei ist beschädigt. Was soll ich tun? Wenn Sie MySQL herunterladen, können Sie die Korruption der Datei begegnen. Es ist heutzutage wirklich nicht einfach! In diesem Artikel wird darüber gesprochen, wie dieses Problem gelöst werden kann, damit jeder Umwege vermeiden kann. Nach dem Lesen können Sie nicht nur das beschädigte MySQL -Installationspaket reparieren, sondern auch ein tieferes Verständnis des Download- und Installationsprozesses haben, um zu vermeiden, dass Sie in Zukunft stecken bleiben. Lassen Sie uns zunächst darüber sprechen, warum das Herunterladen von Dateien beschädigt wird. Dafür gibt es viele Gründe. Netzwerkprobleme sind der Schuldige. Unterbrechung des Download -Prozesses und der Instabilität im Netzwerk kann zu einer Korruption von Dateien führen. Es gibt auch das Problem mit der Download -Quelle selbst. Die Serverdatei selbst ist gebrochen und natürlich auch unterbrochen, wenn Sie sie herunterladen. Darüber hinaus kann das übermäßige "leidenschaftliche" Scannen einer Antiviren -Software auch zu einer Beschädigung von Dateien führen. Diagnoseproblem: Stellen Sie fest, ob die Datei wirklich beschädigt ist

Braucht MySQL das Internet? Braucht MySQL das Internet? Apr 08, 2025 pm 02:18 PM

MySQL kann ohne Netzwerkverbindungen für die grundlegende Datenspeicherung und -verwaltung ausgeführt werden. Für die Interaktion mit anderen Systemen, Remotezugriff oder Verwendung erweiterte Funktionen wie Replikation und Clustering ist jedoch eine Netzwerkverbindung erforderlich. Darüber hinaus sind Sicherheitsmaßnahmen (wie Firewalls), Leistungsoptimierung (Wählen Sie die richtige Netzwerkverbindung) und die Datensicherung für die Verbindung zum Internet von entscheidender Bedeutung.

So optimieren Sie die Datenbankleistung nach der MySQL -Installation So optimieren Sie die Datenbankleistung nach der MySQL -Installation Apr 08, 2025 am 11:36 AM

Die MySQL -Leistungsoptimierung muss von drei Aspekten beginnen: Installationskonfiguration, Indexierung und Abfrageoptimierung, Überwachung und Abstimmung. 1. Nach der Installation müssen Sie die my.cnf -Datei entsprechend der Serverkonfiguration anpassen, z. 2. Erstellen Sie einen geeigneten Index, um übermäßige Indizes zu vermeiden und Abfrageanweisungen zu optimieren, z. B. den Befehl Erklärung zur Analyse des Ausführungsplans; 3. Verwenden Sie das eigene Überwachungstool von MySQL (ShowProcessList, Showstatus), um die Datenbankgesundheit zu überwachen und die Datenbank regelmäßig zu sichern und zu organisieren. Nur durch kontinuierliche Optimierung dieser Schritte kann die Leistung der MySQL -Datenbank verbessert werden.

Wie optimieren Sie die MySQL-Leistung für Hochlastanwendungen? Wie optimieren Sie die MySQL-Leistung für Hochlastanwendungen? Apr 08, 2025 pm 06:03 PM

Die MySQL-Datenbankleistung Optimierungshandbuch In ressourcenintensiven Anwendungen spielt die MySQL-Datenbank eine entscheidende Rolle und ist für die Verwaltung massiver Transaktionen verantwortlich. Mit der Erweiterung der Anwendung werden jedoch die Datenbankleistung Engpässe häufig zu einer Einschränkung. In diesem Artikel werden eine Reihe effektiver Strategien zur Leistungsoptimierung von MySQL -Leistung untersucht, um sicherzustellen, dass Ihre Anwendung unter hohen Lasten effizient und reaktionsschnell bleibt. Wir werden tatsächliche Fälle kombinieren, um eingehende Schlüsseltechnologien wie Indexierung, Abfrageoptimierung, Datenbankdesign und Caching zu erklären. 1. Das Design der Datenbankarchitektur und die optimierte Datenbankarchitektur sind der Eckpfeiler der MySQL -Leistungsoptimierung. Hier sind einige Kernprinzipien: Die Auswahl des richtigen Datentyps und die Auswahl des kleinsten Datentyps, der den Anforderungen entspricht, kann nicht nur Speicherplatz speichern, sondern auch die Datenverarbeitungsgeschwindigkeit verbessern.

Lösungen für den Dienst, der nach der MySQL -Installation nicht gestartet werden kann Lösungen für den Dienst, der nach der MySQL -Installation nicht gestartet werden kann Apr 08, 2025 am 11:18 AM

MySQL hat sich geweigert, anzufangen? Nicht in Panik, lass es uns ausprobieren! Viele Freunde stellten fest, dass der Service nach der Installation von MySQL nicht begonnen werden konnte, und sie waren so ängstlich! Mach dir keine Sorgen, dieser Artikel wird dich dazu bringen, ruhig damit umzugehen und den Mastermind dahinter herauszufinden! Nachdem Sie es gelesen haben, können Sie dieses Problem nicht nur lösen, sondern auch Ihr Verständnis von MySQL -Diensten und Ihren Ideen zur Fehlerbehebungsproblemen verbessern und zu einem leistungsstärkeren Datenbankadministrator werden! Der MySQL -Dienst startete nicht und es gibt viele Gründe, von einfachen Konfigurationsfehlern bis hin zu komplexen Systemproblemen. Beginnen wir mit den häufigsten Aspekten. Grundkenntnisse: Eine kurze Beschreibung des Service -Startup -Prozesses MySQL Service Startup. Einfach ausgedrückt, lädt das Betriebssystem MySQL-bezogene Dateien und startet dann den MySQL-Daemon. Dies beinhaltet die Konfiguration

See all articles