One place for hosting & domains

      hinzufügen

      Hinzufügen von Authentifizierung zu Ihrer App mit Flask-Login


      Einführung

      Die Möglichkeit für Benutzer, sich bei Ihrer Anwendung anzumelden, ist eine der häufigsten Funktionen, die Sie Ihrer Webanwendung hinzufügen werden. Dieser Artikel behandelt, wie Sie Ihrer Flask-Anwendung mit dem Paket Flask-Login Authentifizierung hinzufügen können.

      Animiertes gif der Flask-Anwendung und des Anmeldefelds

      Wir werden einige Registrierungs- und Anmeldeseiten erstellen, die Benutzern die Anmeldung und den Zugriff auf geschützte Seiten ermöglichen, die nicht angemeldete Benutzer nicht sehen können. Wir werden Informationen aus dem Benutzermodell nehmen und sie auf unseren geschützten Seiten anzeigen, wenn sich der Benutzer anmeldet, um zu simulieren, wie ein Profil aussehen würde.

      In diesem Artikel behandeln wir die folgenden Punkte:

      • Verwenden der Bibliothek Flask-Login für die Sitzungsverwaltung.
      • Verwenden des integrierten Dienstprogramms Flask für das Hashing von Passwörtern.
      • Hinzufügen von geschützten Seiten zu unserer Anwendung nur für angemeldete Benutzer.
      • Verwenden von Flask-SQLAlchemy zum Erstellen eines Benutzermodells.
      • Erstellen von Registrierungs- und Anmeldeformularen für unsere Benutzer zur Erstellung von Konten und zum Anmelden.
      • Zurückgeben von Fehlermeldungen an unsere Benutzer, wenn etwas schiefgeht.
      • Verwenden von Informationen aus dem Konto des Benutzers zur Anzeige auf der Profilseite.

      Der Quellcode für dieses Projekt ist auf GitHub verfügbar.

      Voraussetzungen

      Um dieses Tutorial zu absolvieren, benötigen Sie Folgendes:

      Unsere Anwendung wird das Flask Application Factory-Muster mit Blueprints verwenden. Wir werden eine Blueprint haben, die alles im Zusammenhang mit auth (Authentifizierung) behandelt, und eine weitere für unsere regulären Routen, die den Index und die geschützte Profilseite enthalten. In einer echten Anwendung können Sie die Funktionalität nach Belieben aufschlüsseln, aber die hier behandelte Lösung wird für dieses Tutorial gut funktionieren.

      Hier ist ein Diagramm, das einen Eindruck davon vermittelt, wie die Dateistruktur Ihres Projekts nach Abschluss des Tutorials aussehen wird:

      .
      └── flask_auth_app
          └── project
              ├── __init__.py       # setup our app
              ├── auth.py           # the auth routes for our app
              ├── db.sqlite         # our database
              ├── main.py           # the non-auth routes for our app
              ├── models.py         # our user model
              └── templates
                  ├── base.html     # contains common layout and links
                  ├── index.html    # show the home page
                  ├── login.html    # show the login form
                  ├── profile.html  # show the profile page
                  └── signup.html   # show the signup form
      

      Im weiteren Verlauf des Tutorials werden wir diese Verzeichnisse und Dateien erstellen.

      Schritt 1 — Installieren der Pakete

      Es gibt drei Hauptpakete, die wir für unser Projekt benötigen:

      • Flask
      • Flask-Login: zur Handhabung der Benutzersitzungen nach der Authentifizierung
      • Flask-SQLAlchemy: zur Darstellung des Benutzermodells und als Schnittstelle zu unserer Datenbank

      Wir verwenden SQLite, um keine zusätzlichen Abhängigkeiten für die Datenbank installieren zu müssen.

      Zuerst beginnen wir mit der Erstellung des Projektverzeichnisses:

      Als Nächstes müssen wir zum Projektverzeichnis navigieren:

      Falls Sie keine Python-Umgebung haben, werden Sie eine erstellen wollen. Je nachdem, wie Python auf Ihrem Rechner installiert wurde, werden Ihre Befehle in etwa so aussehen:

      • python3 -m venv auth
      • source auth/bin/activate

      Anmerkung: Sie können das für Ihre lokale Umgebung relevante Tutorial zur Einrichtung von venv konsultieren.

      Führen Sie die folgenden Befehle aus Ihrer virtuellen Umgebung aus, um die erforderlichen Pakete zu installieren:

      • pip install flask flask-sqlalchemy flask-login

      Nachdem Sie die Pakete installiert haben, können Sie nun die Hauptanwendungsdatei erstellen.

      Schritt 2 — Erstellen der Hauptanwendungsdatei

      Beginnen wir mit der Erstellung eines Verzeichnisses project:

      Die erste Datei, an der wir arbeiten, wird die Datei __init__.py für unser Projekt sein:

      Diese Datei wird die Funktion zum Erstellen unserer Anwendung haben, die die Datenbank initialisiert und unsere Blueprints registriert. Im Moment bringt das nicht viel, aber es wird für den Rest unserer Anwendung benötigt. Wir müssen SQLAlchemy initialisieren, einige Konfigurationswerte festlegen und unsere Blueprints registrieren.

      project/__init__.py

      from flask import Flask
      from flask_sqlalchemy import SQLAlchemy
      
      # init SQLAlchemy so we can use it later in our models
      db = SQLAlchemy()
      
      def create_app():
          app = Flask(__name__)
      
          app.config['SECRET_KEY'] = 'secret-key-goes-here'
          app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
      
          db.init_app(app)
      
          # blueprint for auth routes in our app
          from .auth import auth as auth_blueprint
          app.register_blueprint(auth_blueprint)
      
          # blueprint for non-auth parts of app
          from .main import main as main_blueprint
          app.register_blueprint(main_blueprint)
      
          return app
      

      Nachdem wir nun die Hauptanwendungsdatei haben, können wir mit dem Hinzufügen unserer Routen beginnen.

      Schritt 3 — Hinzufügen von Routen

      Für unsere Routen verwenden wir zwei Blueprints. Für unsere Haupt-Blueprint haben wir eine Startseite (/) und eine Profilseite (/profile) für nach der Anmeldung. Versucht der Benutzer, ohne angemeldet zu sein, auf die Profilseite zuzugreifen, wird er auf die Anmeldungsroute umgeleitet.

      Für unsere Auth-Blueprint haben wir Routen, um sowohl die Anmeldeseite (/login) als auch die Registrierungsseite (/sign-up) abzurufen. Außerdem haben wir Routen zur Bearbeitung der POST-Anfragen von beiden Routen. Schließlich haben wir eine Abmeldungsroute (/logout), um einen aktiven Benutzer abzumelden.

      Bis auf Weiteres definieren wir login, signup und logout mit einfachen Rückgaben. Wir werden sie in einem späteren Schritt erneut besuchen und mit der gewünschten Funktionalität aktualisieren.

      Erstellen Sie zunächst main.py für Ihre main_blueprint:

      project/main.py

      from flask import Blueprint
      from . import db
      
      main = Blueprint('main', __name__)
      
      @main.route('/')
      def index():
          return 'Index'
      
      @main.route('/profile')
      def profile():
          return 'Profile'
      

      Erstellen Sie als Nächstes auth.py für Ihre auth_blueprint:

      project/auth.py

      from flask import Blueprint
      from . import db
      
      auth = Blueprint('auth', __name__)
      
      @auth.route('/login')
      def login():
          return 'Login'
      
      @auth.route('/signup')
      def signup():
          return 'Signup'
      
      @auth.route('/logout')
      def logout():
          return 'Logout'
      

      In einem Terminal können Sie die Werte FLASK_APP und FLASK_DEBUG festlegen:

      • export FLASK_APP=project
      • export FLASK_DEBUG=1

      Die Umgebungsvariable FLASK_APP weist Flask an, wie die Anwendung geladen werden soll. Sie sollte darauf zeigen, wo sich create_app befindet. Für unsere Bedürfnisse verweisen wir auf das Projektverzeichnis.

      Die Umgebungsvariable FLASK_DEBUG wird durch Einstellung auf 1 aktiviert. Dadurch wird ein Debugger aktiviert, der Anwendungsfehler im Browser anzeigt.

      Stellen Sie sicher, dass Sie sich im Verzeichnis flask_auth_app befinden, und führen Sie dann das Projekt aus:

      Nun sollten Sie in einem Webbrowser in der Lage sein, zu den fünf möglichen URLs zu navigieren und den zurückgegebenen Text zu sehen, der in auth.py und main.py definiert wurde.

      Wenn Sie beispielsweise localhost:5000/profile besuchen, wird angezeigt: Profile:

      Screenshot des Projekts auf localhost Port 5000 im Browser

      Nachdem wir nun verifiziert haben, dass sich unsere Routen wie erwartet verhalten, können wir mit der Erstellung von Vorlagen fortfahren.

      Schritt 4 — Erstellen von Vorlagen

      Fahren wir damit fort, die Vorlagen zu erstellen, die in unserer Anwendung verwendet werden. Dies ist der erste Schritt, bevor wir die tatsächliche Anmeldefunktionalität implementieren können. Unsere Anwendung verwendet vier Vorlagen:

      • index.html
      • profile.html
      • login.html
      • signup.html

      Außerdem haben wir eine Basisvorlage, die einen gemeinsamen Code für jede der Seiten hat. In diesem Fall wird die Basisvorlage Navigationslinks und das allgemeine Layout der Seite enthalten. Lassen Sie uns diese jetzt erstellen.

      Erstellen Sie zunächst ein Verzeichnis templates in dem Verzeichnis project:

      • mkdir -p project/templates

      Erstellen Sie dann base.html:

      • nano project/templates/base.html

      Fügen Sie als Nächstes den folgenden Code in die Datei base.html ein:

      project/templates/base.html

      <!DOCTYPE html>
      <html>
      
      <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <title>Flask Auth Example</title>
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" />
      </head>
      
      <body>
          <section class="hero is-primary is-fullheight">
      
              <div class="hero-head">
                  <nav class="navbar">
                      <div class="container">
      
                          <div id="navbarMenuHeroA" class="navbar-menu">
                              <div class="navbar-end">
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
                                      Home
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
                                      Profile
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
                                      Login
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
                                      Sign Up
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
                                      Logout
                                  </a>
                              </div>
                          </div>
                      </div>
                  </nav>
              </div>
      
              <div class="hero-body">
                  <div class="container has-text-centered">
                     {% block content %}
                     {% endblock %}
                  </div>
              </div>
          </section>
      </body>
      
      </html>
      

      Dieser Code erstellt eine Reihe von Menülinks zu jeder Seite der Anwendung und einen Bereich, in dem der Inhalt angezeigt wird.

      Anmerkung: Hinter den Kulissen verwenden wir Bulma, für das Styling und Layout. Für einen tieferen Einblick in Bulma sollten Sie die offizielle Bulma-Dokumentation lesen.

      Erstellen Sie als Nächstes templates/index.html:

      • nano project/templates/index.html

      Fügen Sie der neu erstellten Datei den folgenden Code hinzu, um Inhalte zu der Seite hinzuzufügen:

      project/templates/index.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Flask Login Example
      </h1>
      <h2 class="subtitle">
        Easy authentication and authorization in Flask.
      </h2>
      {% endblock %}
      

      Dieser Code erstellt eine grundlegende Indexseite mit einem Titel und einem Untertitel.

      Erstellen Sie als Nächstes templates/login.html:

      • nano project/templates/login.html

      Dieser Code generiert eine Anmeldeseite mit Feldern für E-Mail und Passwort. Es gibt auch ein Kontrollkästchen zur „Erinnerung“ an eine angemeldete Sitzung.

      project/templates/login.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Login</h3>
          <div class="box">
              <form method="POST" action="/login">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Your Password">
                      </div>
                  </div>
                  <div class="field">
                      <label class="checkbox">
                          <input type="checkbox">
                          Remember me
                      </label>
                  </div>
                  <button class="button is-block is-info is-large is-fullwidth">Login</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      Erstellen Sie als Nächstes templates/signup.html:

      • nano project/templates/signup.html

      Fügen Sie den folgenden Code hinzu, um eine Registrierungsseite mit Feldern für E-Mail, Namen und Passwort zu erstellen:

      project/templates/signup.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Sign Up</h3>
          <div class="box">
              <form method="POST" action="/signup">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="text" name="name" placeholder="Name" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Password">
                      </div>
                  </div>
      
                  <button class="button is-block is-info is-large is-fullwidth">Sign Up</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      Erstellen Sie als Nächstes templates/profile.html:

      • nano project/templates/profile.html

      Fügen Sie diesen Code hinzu, um eine einfache Seite mit einem Titel zu erstellen, der fest programmiert ist, um Anthony willkommen zu heißen:

      project/templates/profile.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Welcome, Anthony!
      </h1>
      {% endblock %}
      

      Später fügen wir Code hinzu, um jeden Benutzer dynamisch zu begrüßen.

      Sobald Sie die Vorlagen hinzugefügt haben, können wir die Return-Anweisungen in jeder der uns zur Verfügung stehenden Routen aktualisieren, um die Vorlage anstelle des Textes zurückzugeben.

      Aktualisieren Sie als Nächstes main.py durch Ändern der Importzeile und der Routen für index und profile:

      project/main.py

      from flask import Blueprint, render_template
      ...
      @main.route('/')
      def index():
          return render_template('index.html')
      
      @main.route('/profile')
      def profile():
          return render_template('profile.html')
      

      Jetzt aktualisieren Sie auth.py durch Ändern der Importzeile und Routen für login und signup:

      project/auth.py

      from flask import Blueprint, render_template
      ...
      @auth.route('/login')
      def login():
          return render_template('login.html')
      
      @auth.route('/signup')
      def signup():
          return render_template('signup.html')
      

      Sobald Sie diese Änderungen vorgenommen haben, sieht die Registrierungsseite wie folgt aus, wenn Sie zu /sign-up navigieren:

      Registrierungsseite unter /signup

      Sie sollten auch die Seiten für /, /login und /profile sehen können.

      Wir lassen /logout vorerst in Ruhe, da es keine Vorlage anzeigt, wenn wir fertig sind.

      Schritt 5 — Erstellen von Benutzermodellen

      Unser Benutzermodell stellt dar, was es für unsere Anwendung bedeutet, einen Benutzer zu haben. Wir haben Felder für eine E-Mail-Adresse, ein Passwort und einen Namen. In Ihrer Anwendung können Sie entscheiden, ob Sie mehr Informationen pro Benutzer speichern möchten. Sie können Dinge wie Geburtstag, Profilbild, Ort oder beliebige Benutzereinstellungen hinzufügen.

      In Flask-SQLAlchemy erstellte Modelle werden durch Klassen dargestellt, die dann in Tabellen in einer Datenbank übersetzt werden. Die Attribute dieser Klassen werden dann zu Spalten für diese Tabellen.

      Lassen Sie uns fortfahren und dieses Benutzermodell erstellen:

      Dieser Code erstellt ein Benutzermodell mit Spalten für id, email, password und name:

      project/models.py

      from . import db
      
      class User(db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Nachdem Sie ein Benutzermodell erstellt haben, können Sie nun mit der Konfiguration Ihrer Datenbank fortfahren.

      Schritt 6 — Konfigurieren der Datenbank

      Wie in den Voraussetzungen angegeben, verwenden wir eine SQLite-Datenbank. Wir könnten selbst eine SQLite-Datenbank erstellen, aber lassen wir das Flask SQLAlchemy für uns erledigen: Wir haben den Pfad der Datenbank bereits in der Datei __init__.py angegeben. Daher müssen wir Flask-SQLAlchemy nur anweisen, die Datenbank in der Python REPL zu erstellen.

      Wenn Sie Ihre Anwendung stoppen und eine Python REPL öffnen, können wir die Datenbank mit der Methode create_all auf dem Objekt db erstellen. Stellen Sie sicher, dass Sie sich immer noch in der virtuellen Umgebung und im Verzeichnis flask_auth_app befinden.

      • from project import db, create_app
      • db.create_all(app=create_app()) # pass the create_app result so Flask-SQLAlchemy gets the configuration.

      Anmerkung: Wenn die Verwendung des Python-Interpreters für Sie neu ist, können Sie die offizielle Dokumentation konsultieren.

      In Ihrem Projektverzeichnis sehen Sie nun eine Datei db.sqlite. Diese Datenbank wird unsere Benutzertabelle enthalten.

      Schritt 7 — Einrichten der Autorisierungsfunktion

      Für unsere Registrierungsfunktion nehmen wir die Daten, die der Benutzer in das Formular eingibt, und und fügen sie unserer Datenbank hinzu. Bevor wir sie hinzufügen, müssen wir sicherstellen, dass der Benutzer nicht bereits in der Datenbank vorhanden ist. Wenn dies nicht der Fall ist, müssen wir sicherstellen, dass wir das Passwort vor dem Hinzufügen in die Datenbank hashen, da wir unsere Passwörter nicht in Klartext speichern möchten.

      Beginnen wir mit dem Hinzufügen einer zweiten Funktion zur Verarbeitung der POST-Formulardaten. In dieser Funktion werden wir zuerst die vom Benutzer übergebenen Daten sammeln.

      Erstellen Sie die Funktion und fügen Sie ein redirect am Ende hinzu. Dies bietet dem Benutzer die Erfahrung einer erfolgreichen Registrierung und die Weiterleitung zu der Anmeldeseite.

      Aktualisieren Sie auth.py durch Ändern der Importzeile und Implementieren von signup_post:

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          # code to validate and add user to database goes here
          return redirect(url_for('auth.login'))
      

      Fügen wir nun den Rest des Codes hinzu, der für die Registrierung eines Benutzers erforderlich ist.

      Zuerst müssen wir das request-Objekt verwenden, um die Formulardaten zu erhalten.

      Fahren Sie mit der Aktualisierung von auth.py fort, indem Sie Importe hinzufügen und signup_post implementieren:

      auth.py

      from flask import Blueprint, render_template, redirect, url_for, request
      from werkzeug.security import generate_password_hash, check_password_hash
      from .models import User
      from . import db
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          email = request.form.get('email')
          name = request.form.get('name')
          password = request.form.get('password')
      
          user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database
      
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              return redirect(url_for('auth.signup'))
      
          # create a new user with the form data. Hash the password so the plaintext version isn't saved.
          new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256'))
      
          # add the new user to the database
          db.session.add(new_user)
          db.session.commit()
      
          return redirect(url_for('auth.login'))
      

      Anmerkung: Das Speichern von Passwörtern in Klartext wird als schlechte Sicherheitspraxis angesehen. In der Regel möchten Sie einen komplexen Hash-Algorithmus und ein Passwort-Salt verwenden, um Passwörter sicher zu halten.

      Schritt 8 — Testen der Registrierungsmethode

      Nachdem wir nun die Registrierungsmethode abgeschlossen haben, sollten wir in der Lage sein, einen neuen Benutzer zu erstellen. Verwenden Sie das Formular, um einen Benutzer zu erstellen.

      Es gibt zwei Möglichkeiten, wie Sie überprüfen können, ob die Registrierung funktioniert: Sie können einen Datenbankbetrachter verwenden, um die Zeile anzuzeigen, die Ihrer Tabelle hinzugefügt wurde, oder Sie können versuchen, sich mit der gleichen E-Mail-Adresse erneut zu registrieren. Wenn Sie einen Fehler erhalten, wissen Sie, dass die erste E-Mail korrekt gespeichert wurde. Lassen Sie uns also diesen Ansatz wählen.

      Wir können Code hinzufügen, um dem Benutzer mitzuteilen, dass die E-Mail bereits existiert und ihm sagen, dass er zur Anmeldeseite gehen soll. Durch Aufruf der Funktion flash senden wir eine Nachricht an die nächste Anfrage, die in diesem Fall die Weiterleitung „redirect“ ist. Die Seite, auf der wir landen, wird dann Zugriff auf diese Nachricht in der Vorlage haben.

      Zuerst fügen wir die Funktion flash hinzu, bevor wir zurück zu unserer Registrierungsseite umleiten.

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for, request, flash
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          ...
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              flash('Email address already exists')
              return redirect(url_for('auth.signup'))
      

      Um die geflashte Nachricht in der Vorlage zu erhalten, können wir diesen Code oberhalb des Formulars hinzufügen. Dadurch wird die Nachricht direkt über dem Formular angezeigt.

      project/templates/signup.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}. Go to <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}">login page</a>.
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/signup">
      

      Registrierungsfeld, das eine Nachricht anzeigt „E-Mail-Adresse bereits vorhanden. Gehen Sie zur Anmeldeseite“ in einem dunkel-rosa Feld

      Schritt 9 — Hinzufügen der Anmeldemethode

      Die Anmeldemethode ähnelt der Registrierungsfunktion insofern, als dass wir die Benutzerinformationen nehmen und etwas damit tun. In diesem Fall vergleichen wir die eingegebene E-Mail-Adresse, um zu sehen, ob sie in der Datenbank enthalten ist. Wenn dies der Fall ist, testen wir das vom Benutzer bereitgestellte Passwort, indem wir das vom Benutzer eingegebene Passwort hashen und es mit dem gehashten Passwort in der Datenbank vergleichen. Wenn beide gehaschten Passwörter übereinstimmen, wissen wir, dass der Benutzer das korrekte Passwort eingegeben hat.

      Sobald der Benutzer die Passwort-Überprüfung bestanden hat, wissen wir, dass er die richtigen Anmeldedaten hat und wir können in mit Flask-Login anmelden. Durch den Aufruf von login_user erstellt Flask-Login eine Sitzung für diesen Benutzer, die bestehen bleibt, während der Benutzer angemeldet bleibt, wodurch der Benutzer geschützte Seiten einsehen kann.

      Wir können mit einer neuen Route für den Umgang mit den gePOSTeten Dateien beginnen. Wenn sich der Benutzer erfolgreich anmeldet, leiten wir zur Profilseite weiter.

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          # login code goes here
          return redirect(url_for('main.profile'))
      

      Nun müssen wir überprüfen, ob der Benutzer die richtigen Anmeldedaten hat:

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          email = request.form.get('email')
          password = request.form.get('password')
          remember = True if request.form.get('remember') else False
      
          user = User.query.filter_by(email=email).first()
      
          # check if the user actually exists
          # take the user-supplied password, hash it, and compare it to the hashed password in the database
          if not user or not check_password_hash(user.password, password):
              flash('Please check your login details and try again.')
              return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page
      
          # if the above check passes, then we know the user has the right credentials
          return redirect(url_for('main.profile'))
      

      Fügen wir den Block in der Vorlage hinzu, damit der Benutzer die geflashte Nachricht sehen kann. Wie bei dem Registrierungsformular fügen wir die potenzielle Fehlermeldung direkt über dem Formular hinzu:

      project/templates/login.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/login">
      

      Wir haben nun die Möglichkeit zu sagen, dass ein Benutzer erfolgreich angemeldet wurde, aber es ist nichts vorhanden, wo der Benutzer protokolliert werden kann. Hier bringen wir Flask-Login zur Verwaltung von Benutzersitzungen ein.

      Bevor wir beginnen, benötigen wir einige Dinge, damit Flask-Login funktioniert. Beginnen Sie mit dem Hinzufügen des UserMixin zu Ihrem Benutzermodell. Das UserMixin fügt dem Modell Flask-Login-Attribute hinzu, sodass Flask-Login damit arbeiten kann.

      models.py

      from flask_login import UserMixin
      from . import db
      
      class User(UserMixin, db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Dann müssen wir unseren User-Loader angeben. Ein User-Loader teilt Flask-Login mit, wie ein bestimmter Benutzer anhand der in seinem Sitzungs-Cookie gespeicherten ID gefunden werden kann. Wir können dies in unserer Funktion create_app zusammen mit dem Code init für Flask-Login hinzufügen:

      project/__init__.py

      ...
      from flask_login import LoginManager
      ...
      def create_app():
          ...
          db.init_app(app)
      
          login_manager = LoginManager()
          login_manager.login_view = 'auth.login'
          login_manager.init_app(app)
      
          from .models import User
      
          @login_manager.user_loader
          def load_user(user_id):
              # since the user_id is just the primary key of our user table, use it in the query for the user
              return User.query.get(int(user_id))
      

      Schließlich können wir die Funktion login_user hinzufügen, kurz bevor wir auf die Profilseite zur Erstellung der Sitzung weiterleiten:

      project/auth.py

      from flask_login import login_user
      from .models import User
      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          ...
          # if the above check passes, then we know the user has the right credentials
          login_user(user, remember=remember)
          return redirect(url_for('main.profile'))
      

      Mit der Einrichtung von Flask-Login können wir die Route /login verwenden. Wenn alles eingerichtet ist, sehen Sie die Profilseite.

      Profilseite mit „Willkommen, Anthony!“

      Schritt 10 — Schützen von Seiten

      Wenn Ihr Name nicht auch Anthony ist, werden Sie feststellen, dass Ihr Name falsch ist. Wir möchten, dass das Profil den Namen in der Datenbank anzeigt. Zuerst müssen wir also die Seite schützen und dann auf die Daten des Benutzers zugreifen, um den Namen zu erhalten.

      Um eine Seite bei der Verwendung von Flask-Login zu schützen, fügen wir den Dekorator @login_requried zwischen der Route und der Funktion hinzu. Dadurch wird verhindert, dass ein nicht angemeldeter Benutzer die Route sehen kann. Wenn der Benutzer nicht angemeldet ist, wird der Benutzer gemäß der Flask-Login-Konfiguration auf die Anmeldeseite weitergeleitet.

      Bei Routen, die mit dem Dekorator @login_required versehen sind, haben wir dann die Möglichkeit, das Objekt current_user innerhalb der Funktion zu verwenden. Dieser current_user stellt den Benutzer aus der Datenbank dar und wir können mit der Punktnotation auf alle Attribute dieses Benutzers zugreifen. Beispielsweise geben current_user.email, current_user.password und current_user.name sowie current_user.id die tatsächlichen Werte zurück, die in der Datenbank für den angemeldeten Benutzer gespeichert sind.

      Verwenden wir den Namen des aktuellen Benutzers und senden ihn an die Vorlage. Dann verwenden wir diesen Namen und zeigen seinen Wert an.

      project/main.py

      from flask_login import login_required, current_user
      ...
      @main.route('/profile')
      @login_required
      def profile():
          return render_template('profile.html', name=current_user.name)
      

      Aktualisieren Sie dann in der Datei profile.html die Seite, um den Wert name anzuzeigen:

      project/templates/profile.html

      ...
      <h1 class="title">
        Welcome, {{ name }}!
      </h1>
      

      Sobald wir zu unserer Profilseite gehen, sehen wir, dass der Name des Benutzers angezeigt wird.

      Begrüßungsseite für den Benutzer mit dem Namen des aktuell angemeldeten Benutzers

      Als Letztes können wir die Abmelde-Ansicht aktualisieren. Wir können die Funktion logout_user in einer Route zur Abmeldung aufrufen. Wir haben den Dekorator @login_required, weil es keinen Sinn macht, einen Benutzer abzumelden, der nicht zuerst angemeldet ist.

      project/auth.py

      from flask_login import login_user, logout_user, login_required
      ...
      @auth.route('/logout')
      @login_required
      def logout():
          logout_user()
          return redirect(url_for('main.index'))
      

      Nachdem wir uns abgemeldet und versucht haben, die Profilseite erneut anzuzeigen, wird eine Fehlermeldung angezeigt. Dies liegt daran, dass Flask-Login eine Nachricht für uns anzeigt, wenn der Benutzer nicht auf eine Seite zugreifen darf.

      Anmeldeseite mit einer Nachricht, die zeigt, dass sich der Benutzer anmelden muss, um auf die Seite zuzugreifen.

      Eine letzte Sache, die wir tun können, ist, if-Anweisungen in die Vorlage aufzunehmen, um nur die für den Benutzer relevanten Links anzuzeigen. Bevor sich der Benutzer also anmeldet, hat er die Möglichkeit, sich anzumelden oder zu registrieren. Nach der Anmeldung können Benutzer zu ihrem Profil gehen oder sich abmelden:

      templates/base.html

      ...
      <div class="navbar-end">
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
              Home
          </a>
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
              Profile
          </a>
          {% endif %}
          {% if not current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
              Login
          </a>
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
              Sign Up
          </a>
          {% endif %}
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
              Logout
          </a>
          {% endif %}
      </div>
      

      Startseite mit der Navigation Start, Anmeldung und Registrierung oben auf dem Bildschirm

      Damit haben Sie Ihre Anwendung mit Authentifizierung erfolgreich erstellt.

      Zusammenfassung

      Wir haben Flask-Login und Flask-SQLAlchemy verwendet, um ein Anmeldesystem für unsere Anwendung zu erstellen. Wir haben behandelt, wie ein Benutzer authentifiziert werden kann, indem wir zuerst ein Benutzermodell erstellen und die Benutzerinformationen speichern. Dann mussten wir verifizieren, dass das Passwort des Benutzers korrekt war, indem wir das Passwort aus dem Formular gehasht und mit dem in der Datenbank gespeicherten Benutzer verglichen haben. Schließlich haben wir unserer Anwendung Autorisierung hinzugefügt, indem wir den Dekorator @login_required auf einer Profilseite verwenden, damit nur angemeldete Benutzer diese Seite sehen können.

      Was wir in diesem Tutorial erstellt haben, wird für kleinere Anwendungen ausreichen. Wenn Sie jedoch von Anfang an mehr Funktionalität haben möchten, sollten Sie möglicherweise die Bibliotheken Flask-User oder Flask-Security verwenden, die beide auf der Bibliothek Flask-Login aufbauen.



      Source link

      Hinzufügen und Löschen von Benutzern unter CentOS 8


      Einführung

      Wenn Sie zum ersten Mal einen neuen Linux-Server einsetzen, ist das Hinzufügen und Entfernen von Benutzern oft eines der ersten Dinge, die Sie tun müssen.  In diesem Leitfaden erfahren Sie, wie Sie auf einem CentOS 8-Server Benutzerkonten erstellen, sudo-Privilegien zuweisen und Benutzer löschen.

      Voraussetzungen

      In diesem Tutorial wird davon ausgegangen, dass Sie mit einem non-root sudo-fähigen user an einem CentOS 8-Server angemeldet sind. Wenn Sie stattdessen als root angemeldet sind, können Sie den sudo-Teil aller folgenden Befehle weglassen, aber sie funktionieren so oder so.

      Hinzufügen von Benutzern

      Während des gesamten Tutorials werden wir mit dem Benutzer sammy arbeiten. Bitte ersetzen Sie ihn mit dem Benutzernamen Ihrer Wahl.

      Sie können einen neuen Benutzer hinzufügen, indem Sie Folgendes eingeben:

      Als Nächstes müssen Sie Ihrem Benutzer ein Passwort geben, damit er sich anmelden kann. Benutzen Sie hierfür den Befehl passwd:

      Sie werden aufgefordert, das Passwort zweimal einzugeben, um es zu bestätigen. Nun ist Ihr neuer Benutzer eingerichtet und einsatzbereit!

      Anmerkung: Wenn Ihr SSH-Server passwortbasierte Authentifizierung nicht zulässt, können Sie noch keine Verbindung mit Ihrem neuen Benutzernamen herstellen. Einzelheiten zur Einrichtung der schlüsselbasierten SSH-Authentifizierung für den neuen Benutzer finden Sie in Schritt 5 von Ersteinrichtung des Servers unter CentOS 8.

      Erteilen von Sudo-Berechtigungen an einen Benutzer

      Wenn Ihr neuer Benutzer in der Lage sein soll, Befehle mit (administrativen) root-Berechtigungen auszuführen, müssen Sie ihm Zugriff auf sudo gewähren.

      Wir können dies tun, indem wir den Benutzer zu der Gruppe wheel hinzufügen (die standardmäßig allen ihren Mitgliedern Zugriff auf sudo gewährt).

      Verwenden Sie den Befehl usermod, um den Benutzer der Guppe wheel hinzuzufügen:

      • sudo usermod -aG wheel sammy wheel

      Jetzt kann Ihr neuer Benutzer Befehle mit administrativen Berechtigungen ausführen. Stellen Sie dazu sudo dem Befehl voran, den Sie als Administrator ausführen möchten:

      Sie werden aufgefordert, das Passwort Ihres Benutzerkontos einzugeben (nicht das root-Passwort). Sobald das korrekte Passwort eingegeben wurde, wird der von Ihnen eingegebene Befehl mit root-Berechtigungen ausgeführt.

      Verwalten von Benutzern mit Sudo-Berechtigungen

      Während Sie mit usermod Benutzer zu einer Gruppe hinzufügen und aus einer Gruppe entfernen können, hat der Befehl keine Möglichkeit, anzuzeigen, welche Benutzer Mitglieder einer Gruppe sind.

      Um zu sehen, welche Benutzer Teil der Guppe wheel sind (und somit sudo-Berechtigungen haben), können Sie den Befehl lid verwenden. lid wird normalerweise verwendet, um anzuzeigen, zu welchen Gruppen ein Benutzer gehört. Aber mit dem Flag -g können Sie es umkehren und anzeigen, welche Benutzer zu einer Gruppe gehören:

      Output

      centos(uid=1000) sammy(uid=1001)

      Die Ausgabe wird Ihnen die mit der Gruppe verbundenen Benutzernamen und UIDs zeigen. Dies ist eine gute Möglichkeit, um zu bestätigen, dass Ihre vorherigen Befehle erfolgreich waren und dass der Benutzer über die erforderlichen Berechtigungen verfügt.

      Löschen von Benutzern

      Wenn Sie ein Benutzerkonto haben, das Sie nicht mehr benötigen, ist es am besten, es zu löschen.

      Um den Benutzer zu löschen, ohne eine seiner Dateien zu löschen, verwenden Sie den Befehl userdel:

      Wenn Sie das Home-Verzeichnis des Benutzers zusammen mit seinem Konto löschen wollen, fügen Sie das Flag -r zu userdel hinzu:

      Mit beiden Befehlen wird der Benutzer automatisch aus allen Gruppen entfernt, denen er hinzugefügt wurde, einschließlich der Gruppe wheel, falls zutreffend. Wenn Sie später einen weiteren Benutzer mit dem gleichen Namen hinzufügen, müssen Sie ihn wieder der Gruppe wheel hinzufügen, um sudo-Zugriff zu erhalten.

      Zusammenfassung

      Sie sollten nun einen guten Überblick über das Hinzufügen und Löschen von Benutzern von Ihrem CentOS 8-Server haben. Eine effektive Benutzerverwaltung ermöglicht es Ihnen, Benutzer zu trennen und ihnen nur den Zugriff zu gewähren, den sie für ihre Arbeit benötigen.

      Sie können nun damit fortfahren, Ihren CentOS 8-Server für die Software zu konfigurieren, die Sie benötigen, wie z. B. einen LAMP- oder LEMP-Web-Stack.



      Source link

      Sidekiq und Redis einer Ruby-on-Rails-Anwendung hinzufügen


      Einführung

      Bei der Entwicklung einer Ruby-on-Rails-Anwendung stellen Sie möglicherweise fest, dass Sie Anwendungsaufgaben haben, die asynchron ausgeführt werden sollten. Die Verarbeitung von Daten, das Versenden von Batch-E-Mails oder die Interaktion mit externen APIs sind Beispiele für Arbeiten, die asynchron mit Hintergrundjobs durchgeführt werden können. Die Verwendung von Hintergrundjobs kann die Leistung Ihrer Anwendung verbessern, indem möglicherweise zeitintensive Aufgaben in eine Hintergrundverarbeitungs-Warteschlange ausgelagert werden, wodurch der ursprüngliche Anfrage-/Antwort-Zyklus entlastet wird.

      Sidekiq ist eines der am häufigsten verwendeten Hintergrundjob-Frameworks, das Sie in einer Rails-Anwendung implementieren können. Es wird von Redis unterstützt, einem In-Memory-Schlüsselwertspeicher, der für seine Flexibilität und Leistung bekannt ist. Sidekiq verwendet Redis als Aufgabenmanagementspeicher, um pro Sekunde Tausende von Aufgaben zu verarbeiten.

      In diesem Tutorial fügen Sie Redis und Sidekiq zu einer bestehenden Rails-Anwendung hinzu. Sie werden einen Satz von Sidekiq Worker-Klassen und -Verfahren erstellen, um Folgendes zu bewältigen:

      • Einen Batch-Upload von Informationen über bedrohte Haie in die Anwendungsdatenbank aus einer CSV-Datei im Projekt-Repository.
      • Die Entfernung dieser Daten.

      Wenn Sie fertig sind, haben Sie eine Demo-Anwendung, die Workers und Jobs verwendet, um Aufgaben asynchron zu verarbeiten. Dieses Tutorial ist ein guter Startpunkt, damit Sie später Worker und Jobs zu Ihrer eigenen Anwendung hinzufügen können.

      Voraussetzungen

      Um dieser Anleitung zu folgen, benötigen Sie:

      Schritt 1 – Klonen des Projekts und Installieren von Abhängigkeiten

      Unser erster Schritt besteht darin, das Repository rails-bootstrap aus dem DigitalOcean Community GitHub-Konto zu klonen. Dieses Repository enthält den Code aus dem Setup, das in „Hinzufügen von Sidekiq und Redis zu einer Ruby-on-Rails-Anwendung“ beschrieben wird. Dort wird erklärt, wie Bootstrap zu einem bestehenden Rails 5-Projekt hinzugefügt wird.

      Klonen Sie das Repository in ein Verzeichnis namens rails-sidekiq:

      • git clone https://github.com/do-community/rails-bootstrap.git rails-sidekiq

      Navigieren Sie zum Verzeichnis rails-sidekiq:

      Um mit dem Code arbeiten zu können, müssen Sie zunächst die Abhängigkeiten des Projekts installieren, die in seiner Gemfile aufgelistet sind. Um mit Sidekiq und Redis arbeiten zu können, müssen Sie dem Projekt auch das Gem sidekiq hinzufügen.

      Öffnen Sie das Gemfile des Projekts zur Bearbeitung mit nano oder Ihrem bevorzugten Editor:

      Fügen Sie das Gem an beliebiger Stelle in die Abhängigkeiten des Hauptprojekts ein (oberhalb der Entwicklungsabhängigkeiten):

      ~/rails-sidekiq/Gemfile

      . . .
      # Reduces boot times through caching; required in config/boot.rb
      gem 'bootsnap', '>= 1.1.0', require: false
      gem 'sidekiq', '~>6.0.0'
      
      group :development, :test do
      . . .
      

      Speichern und schließen Sie die Datei, wenn Sie mit dem Hinzufügen des Gems fertig sind.

      Verwenden Sie den folgenden Befehl, um die Gems zu installieren:

      Sie werden in der Ausgabe sehen, dass das Gem redis auch als Erfordernis für sidekiq installiert ist.

      Als Nächstes installieren Sie Ihre Yarn-Abhängigkeiten. Da dieses Rails 5-Projekt modifiziert wurde, um Assets mit webpack bereitzustellen, werden seine JavaScript-Abhängigkeiten nun von Yarn verwaltet. Das bedeutet es ist notwendig, die in der Datei package.json des Projekts aufgeführten Abhängigkeiten zu installieren und zu verifizieren.

      Führen Sie yarn install aus, um diese Abhängigkeiten zu installieren:

      Führen Sie als Nächstes Ihre Datenbankmigration durch:

      Sobald Ihre Migrationen abgeschlossen sind, können Sie die Anwendung testen, um sicherzustellen, dass sie wie erwartet funktioniert. Starten Sie Ihren Server im Kontext Ihres lokalen Bundles mit dem folgenden Befehl, wenn Sie lokal arbeiten:

      Wenn Sie auf einem Entwicklungsserver arbeiten, können Sie die Anwendung starten mit:

      • bundle exec rails s --binding=your_server_ip

      Navigieren Sie zu localhost:3000 oder http://your_server_ip:3000. Sie sehen die folgende Startseite:

      Anwendungs-Startseite

      Um einen neuen Hai zu erstellen, klicken Sie auf die Schaltfläche Get Shark Info, die Sie zu der Route sharks/index führt:

      Sharks Index-Route

      Um zu verifizieren, dass die Anwendung funktioniert, können wir ihr einige Demo-Informationen anhängen. Klicken Sie auf New Shark. Dank der Authentifizierungseinstellungen des Projekts werden Sie zur Eingabe des Benutzernamens (sammy) und Passworts (shark) aufgefordert.

      Geben Sie auf der Seite New Shark unter Name „Great White“ und unter Facts „Scary“ ein:

      Hai erstellen

      Klicken Sie auf die Schaltfläche Create Shark, um den Shark zu erstellen. Sobald Sie sehen, dass Ihr Hai erstellt wurde, können Sie den Server mit STRG+C beenden.

      Sie haben nun die notwendigen Abhängigkeiten für Ihr Projekt installiert und seine Funktionalität getestet. Als Nächstes können Sie einige Änderungen der Rails-Anwendung vornehmen, um mit Ihren Ressourcen für bedrohte Haie zu arbeiten.

      Schritt 2 — Generieren eines Controllers für Ressourcen für bedrohte Haie

      Um mit unseren Ressourcen für bedrohte Haie zu arbeiten, fügen wir der Anwendung ein neues Modell und einen Controller hinzu, der steuert, wie den Benutzern Informationen über bedrohte Haie präsentiert werden. Unser ultimatives Ziel ist, den Benutzern das Hochladen einer großen Menge von Informationen über bedrohte Haie zu ermöglichen, ohne die Gesamtfunktionalität unserer Anwendung zu blockieren, und diese Informationen zu löschen, wenn sie sie nicht mehr benötigen.

      Erstellen wir zunächst ein Modell Endangered für unsere bedrohten Haie. Wir werden ein Zeichenfolgenfeld für den Hainamen in unsere Datenbanktabelle aufnehmen und ein weiteres Zeichenfolgenfeld für die Kategorien der International Union for the Conservation of Nature (IUCN), die den Grad der Gefährdung der einzelnen Haie bestimmen.

      Letztendlich entspricht unsere Modellstruktur den Spalten in der CSV-Datei, die wir zur Erstellung unseres Batch-Uploads verwenden werden. Diese Datei befindet sich im Verzeichnis db und Sie können ihren Inhalt mit dem folgenden Befehl überprüfen:

      Die Datei enthält eine Liste von 73 bedrohten Haien und ihren IUCN-Status – vu für gefährdet, en für bedroht und cr für vom Aussterben bedroht.

      Unser Modell Endangered wird mit diesen Daten übereinstimmen, sodass wir neue Instanzen Endangered aus dieser CSV-Datei erstellen können. Erstellen Sie das Modell mit dem folgenden Befehl:

      • rails generate model Endangered name:string iucn:string

      Erstellen Sie als Nächstes einen Controller Endangered mit einer Aktion index:

      • rails generate controller endangered index

      Dadurch erhalten wir einen Ausgangspunkt, um die Funktionalität unserer Anwendung auszubauen, obwohl wir auch benutzerdefinierte Methoden zu der Controller-Datei hinzufügen müssen, die Rails für uns generiert hat.

      Öffnen Sie nun diese Datei:

      • nano app/controllers/endangered_controller.rb

      Rails hat uns ein Grundgerüst zur Verfügung gestellt, das wir nun ausfüllen können.

      Zunächst müssen wir bestimmen, welche Routen wir für die Arbeit mit unseren Daten benötigen. Dank dem Befehl generate controller haben wir eine Methode index, mit der wir beginnen können. Diese wird mit einer Ansicht index korrelieren, in der wir den Benutzern die Möglichkeit bieten werden, bedrohte Haie hochzuladen.

      Wir werden aber auch Fälle bearbeiten wollen, in denen Benutzer die Haie möglicherweise bereits hochgeladen haben. In diesem Fall benötigen sie keine Upload-Option. Wir werden irgendwie beurteilen müssen, wie viele Instanzen der Klasse Endangered bereits existieren, da mehr als eine darauf hinweist, dass der Batch-Upload bereits stattgefunden hat.

      Beginnen wir mit der Erstellung einer Methode private set_endangered, die jede Instanz unserer Klasse Endangered aus der Datenbank abrufen wird. Fügen Sie den folgenden Code zur Datei hinzu:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      class EndangeredController < ApplicationController
        before_action :set_endangered, only: [:index, :data]
      
        def index
        end
      
        private
      
          def set_endangered
            @endangered = Endangered.all
          end
      
      end
      

      Beachten Sie, dass der Filter before_action sicherstellt, dass der Wert von @endangered nur für die Routen index und data festgelegt ist. Dort verarbeiten wir die Daten über bedrohte Haie.

      Fügen Sie als Nächstes den folgenden Code zu der Methode index hinzu, um den richtigen Pfad für Benutzer zu bestimmen, die diesen Teil der Anwendung besuchen:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      class EndangeredController < ApplicationController
        before_action :set_endangered, only: [:index, :data]
      
        def index          
          if @endangered.length > 0
            redirect_to endangered_data_path
          else
            render 'index'
          end
        end
      . . .
      

      Wenn mehr als 0 Instanzen unserer Klasse Endangered vorhanden sind, leiten wird die Benutzer auf die Route data um, wo sie Informationen über die von ihnen erstellten Haie einsehen können. Andernfalls sehen sie die Ansicht index.

      Fügen Sie als Nächstes unter die Methode index eine Methode data hinzu, die mit der Ansicht data korreliert:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      . . .
        def index          
          if @endangered.length > 0
            redirect_to endangered_data_path
          else
            render 'index'
          end
        end
      
        def data
        end
      . . .
      

      Als Nächstes fügen wir eine Methode hinzu, um den Daten-Upload selbst zu verarbeiten. Wir nennen diese Methode upload und sie wird eine Sidekiq Worker-Klasse und -methode aufrufen, um den Daten-Upload aus der CSV-Datei durchzuführen. Im nächsten Schritt erstellen wir die Definition für diese Worker-Klasse, AddEndangeredWorker.

      Für den Moment fügen Sie den folgenden Code zu der Datei hinzu, um den Sidekiq Worker aufzurufen, der den Upload ausführt:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      . . .
        def data
        end
      
        def upload
          csv_file = File.join Rails.root, 'db', 'sharks.csv'   
          AddEndangeredWorker.perform_async(csv_file)
          redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!'
        end
      . . .
      

      Durch den Aufruf der Methode perform_async in der Klasse AddEndangeredWorker mit der CSV-Datei als Argument, stellt dieser Code sicher, dass die Haidaten und der Upload-Job an Redis übergeben werden. Die Sidekiq Workers, die wir einrichten werden, überwachen die Job-Warteschlange und reagieren, wenn neue Jobs entstehen.

      Nach dem Aufruf von perform_async leitet unsere Methode upload zu dem Pfad data um, wo Benutzer die hochgeladenen Haie einsehen können.

      Als Nächstes fügen wir eine Methode destroy zur Zerstörung der Daten hinzu. Fügen Sie den folgenden Code unter die Methode upload hinzu:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      . . .
        def upload
          csv_file = File.join Rails.root, 'db', 'sharks.csv'   
          AddEndangeredWorker.perform_async(csv_file)
          redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!'
        end
      
        def destroy
          RemoveEndangeredWorker.perform_async
          redirect_to root_path
        end
      . . .
      

      Wie unsere Methode upload beinhaltet unsere Methode destroy einen Aufruf perform_async der Klasse RemoveEndangeredWorker – den anderen Sidekiq Worker, den wir erstellen werden. Nach dem Aufruf dieser Methode leitet sie die Benutzer zu dem Stammanwendungspfad um.

      Die fertige Datei sieht ungefähr so aus:

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      class EndangeredController < ApplicationController
        before_action :set_endangered, only: [:index, :data]
      
        def index          
          if @endangered.length > 0
            redirect_to endangered_data_path
          else
            render 'index'
          end
        end
      
        def data
        end
      
        def upload
          csv_file = File.join Rails.root, 'db', 'sharks.csv'   
          AddEndangeredWorker.perform_async(csv_file)
          redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!'
        end
      
        def destroy
          RemoveEndangeredWorker.perform_async
          redirect_to root_path
        end
      
        private
      
          def set_endangered
            @endangered = Endangered.all
          end
      
      end
      

      Wenn die Bearbeitung abgeschlossen wurde, speichern und schließen Sie die Datei.

      Als letzten Schritt zur Verfestigung der Routen unserer Anwendung werden wir den Code config/routes.rb der Datei, in der sich unsere Routendeklarationen befinden, ändern.

      Öffnen Sie nun diese Datei:

      Die Datei sieht derzeit wie folgt aus:

      ~/rails-sidekiq/config/routes.rb

      Rails.application.routes.draw do
        get 'endangered/index'
        get 'home/index'
        resources :sharks do
                resources :posts
        end
        root 'home#index'
        # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
      end
      

      Wir müssen die Datei aktualisieren, um die in unserem Controller definierten Routen aufzunehmen: data, upload und destroy. Unsere Route data wird mit einer GET-Anforderung zum Abrufen der Haifischdaten übereinstimmen, während unsere Routen upload und destroy den POST-Anforderungen zugeordnet werden, die diese Daten hochladen und zerstören.

      Fügen Sie den folgenden Code zu der Datei hinzu, um diese Routen zu definieren:

      ~/rails-sidekiq/config/routes.rb

      Rails.application.routes.draw do
        get 'endangered/index'
        get 'endangered/data', to: 'endangered#data'
        post 'endangered/upload', to: 'endangered#upload'
        post 'endangered/destroy', to: 'endangered#destroy'
        get 'home/index'
        resources :sharks do
                resources :posts
        end
        root 'home#index'
        # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
      end
      

      Wenn die Bearbeitung abgeschlossen wurde, speichern und schließen Sie die Datei.

      Nachdem Sie Ihr Modell Endangered und Ihre Controller eingerichtet haben, können Sie nun mit der Definition Ihrer Sidekiq Worker-Klassen fortfahren.

      Schritt 3 – Definieren von Sidekiq Workers

      Wir haben die Methode perform_async für unsere Sidekiq Worker in unserem Controller aufgerufen, aber wir müssen noch die Worker selbst erstellen.

      Erstellen Sie zunächst ein Verzeichnis workers für die Worker:

      Öffnen Sie eine Datei für den Worker AddEndangeredWorker:

      • nano app/workers/add_endangered_worker.rb

      Wir fügen in dieser Datei Code ein, der uns die Arbeit mit den Daten in unserer CSV-Datei ermöglicht. Zunächst fügen wir der Datei Code hinzu, der die Klasse erstellt, die Ruby-CSV-Bibliothek einbezieht und sicherstellt, dass diese Klasse als Sidekiq Worker funktioniert:

      ~/rails-sidekiq/app/workers/add_endangered_worker.rb

      class AddEndangeredWorker
        require 'csv'
        include Sidekiq::Worker
        sidekiq_options retry: false
      
      end
      

      Wir fügen auch die Option retry: false ein, um sicherzustellen, dass Sidekiq den Upload im Falle eines Fehlschlags nicht erneut versucht.

      Fügen Sie als Nächstes den Code für die Funktion perform hinzu:

      ~/rails-sidekiq/app/workers/add_endangered_worker.rb

      class AddEndangeredWorker
        require 'csv'
        include Sidekiq::Worker
        sidekiq_options retry: false
      
        def perform(csv_file)
          CSV.foreach(csv_file, headers: true) do |shark|
          Endangered.create(name: shark[0], iucn: shark[1])
        end
       end
      
      end
      

      Die Methode perform empfängt Argumente von der im Controller definierten Methode perform_async. Daher ist es wichtig, dass die Argumentwerte abgeglichen sind. Hier übergeben wir in csv_file, die in dem Controller definierte Variable und verwenden die Methode foreach aus der CSV-Bibliothek, um die Werte in der Datei zu lesen. Das Setzen von headers: true für diese Schleife stellt sicher, dass die erste Zeile der Datei als eine Zeile von Headers behandelt wird.

      Der Block liest dann die Werte von der Datei in die Spalten, die wir für unser Modell Endangered festgelegt haben: name und iucn. Durch Ausführung dieser Schleife werden für jeden der Einträge in unserer CSV-Datei Instanzen Endangered erstellt.

      Wenn Sie die Bearbeitung abgeschlossen haben, speichern und schließen Sie die Datei.

      Als Nächstes erstellen wir einen Worker, der sich um das Löschen dieser Daten kümmert. Öffnen Sie eine Datei für die Klasse RemoveEndangeredWorker:

      • nano app/workers/remove_endangered_worker.rb

      Fügen Sie den Code zur Definition der Klasse hinzu und stellen Sie sicher, dass sie die CSV-Bibliothek verwendet und als Sidekiq Worker funktioniert:

      ~/rails-sidekiq/app/workers/remove_endangered_worker.rb

      class RemoveEndangeredWorker
        include Sidekiq::Worker
        sidekiq_options retry: false
      
      end
      

      Fügen Sie als Nächstes eine Methode perform hinzu, um die Zerstörung der Daten von bedrohten Haien zu handhaben:

      ~/rails-sidekiq/app/workers/remove_endangered_worker.rb

      class RemoveEndangeredWorker
        include Sidekiq::Worker
        sidekiq_options retry: false
      
        def perform
          Endangered.destroy_all
        end
      
      end
      

      Die Methode perform ruft destroy_all in der Klasse Endangered auf, wodurch alle Instanzen der Klasse aus der Datenbank entfernt werden.

      Wenn die Bearbeitung abgeschlossen wurde, speichern und schließen Sie die Datei.

      Nachdem Sie Ihre Worker eingerichtet haben, können Sie mit der Erstellung eines Layouts für Ihre Ansichten endangered und von Vorlagen für Ihre Ansichten index und data fortfahren, sodass Benutzer bedrohte Haie hochladen und ansehen können.

      Schritt 4 – Hinzufügen von Layouts und Ansichtsvorlagen

      Damit Benutzer in den Genuss ihrer Informationen über bedrohte Haie kommen, müssen wir uns mit zwei Dingen befassen: dem Layout für die in unserem Controller endangered definierten Ansichten und mit den Ansichtsvorlagen für die Ansichten index und data.

      Unsere Anwendung verwendet derzeit ein anwendungsweites Layout, das sich unter app/views/layouts/application.html.erb befindet, eine Navigations-Partiale und ein Layout für die Ansichten sharks. Das Anwendungslayout prüft, ob ein Inhaltsblock vorhanden ist, der das Laden verschiedener Layouts ermöglicht, je nachdem, mit welchem Teil der Anwendung sich unsere Benutzer beschäftigen: für die Seite home index sehen sie ein Layout und für alle Ansichten über individuelle Haie ein anderes.

      Wir können das Layout sharks für unsere Ansichten endangered neu verwenden, da dieses Format auch für die Darstellung von Haidaten in großen Mengen funktioniert.

      Kopieren Sie die Layoutdatei sharks, um ein Layout für endangered zu erstellen:

      • cp app/views/layouts/sharks.html.erb app/views/layouts/endangered.html.erb

      Als Nächstes werden wir an der Erstellung von Ansichtenvorlagen für unsere Ansichten index und data arbeiten.

      Öffnen Sie zuerst die Vorlage index:

      • nano app/views/endangered/index.html.erb

      Löschen Sie den Boilerplate-Code und fügen Sie stattdessen den folgenden Code hinzu, der den Benutzern einige allgemeine Informationen über die bedrohten Kategorien gibt und ihnen die Möglichkeit bietet, Informationen über bedrohte Haie hochzuladen:

      ~/rails-sidekiq/app/views/endangered/index.html.erb

      <p id="notice"><%= notice %></p>
      
      <h1>Endangered Sharks</h1>
      
      <p>International Union for Conservation of Nature (ICUN) statuses: <b>vu:</b> Vulnerable, <b>en:</b> Endangered, <b>cr:</b> Critically Endangered </p>
      
      <br>
      
        <%= form_tag endangered_upload_path do %>
        <%= submit_tag "Import Endangered Sharks" %>
        <% end %>
      
        <br>
      
      <%= link_to 'New Shark', new_shark_path, :class => "btn btn-primary btn-sm" %> <%= link_to 'Home', home_index_path, :class => "btn btn-primary btn-sm" %>
      

      Ein form_tag macht den Daten-Upload möglich, indem eine Post-Aktion auf den endangered_upload_path verweist – die Route, die wir für unsere Uploads definiert haben.  Eine Submit-Schaltfläche, die mit dem submit_tag erstellt wurde, fordert die Benutzer zum "Import Endangered Sharks" (Importieren bedrohter Haie) auf.

      Zusätzlich zu diesem Code haben wir einige allgemeine Informationen über ICUN-Codes eingefügt, damit die Benutzer die Daten, die sie sehen werden, interpretieren können.

      Wenn die Bearbeitung abgeschlossen wurde, speichern und schließen Sie die Datei.

      Öffnen Sie als Nächstes eine Datei für die Ansicht data:

      • nano app/views/endangered/data.html.erb

      Fügen Sie den folgenden Code hinzu, der eine Tabelle mit den Daten der bedrohten Haie hinzufügt:

      ~/rails-sidekiq/app/views/endangered/data.html.erb

      <p id="notice"><%= notice %></p>
      
      <h1>Endangered Sharks</h1>
      
      <p>International Union for Conservation of Nature (ICUN) statuses: <b>vu:</b> Vulnerable, <b>en:</b> Endangered, <b>cr:</b> Critically Endangered </p>
      
      <div class="table-responsive">
      <table class="table table-striped table-dark">
        <thead>
          <tr>
            <th>Name</th>
            <th>IUCN Status</th>
            <th colspan="3"></th>
          </tr>
        </thead>
      
        <tbody>
          <% @endangered.each do |shark| %>
            <tr>
              <td><%= shark.name %></td>
              <td><%= shark.iucn %></td>
            </tr>
          <% end %>
        </tbody>
      </table>
      </div>
      
      <br>
      
        <%= form_tag endangered_destroy_path do %>
        <%= submit_tag "Delete Endangered Sharks" %>
        <% end %>
      
        <br>
      
      <%= link_to 'New Shark', new_shark_path, :class => "btn btn-primary btn-sm" %> <%= link_to 'Home', home_index_path, :class => "btn btn-primary btn-sm" %>
      

      Dieser Code enthält noch einmal die ICUN-Statuscodes und eine Bootstrap-Tabelle für die ausgegebenen Daten. Indem wir unsere Variable @endangered durchschleifen, geben wir den Namen und den ICUN-Status jedes Hais in die Tabelle aus.

      Unterhalb der Tabelle haben wir einen weiteren Satz von form_tags und submit_tags, die auf den Pfad destroy verweisen, indem Benutzern die Option zum "Delete Endangered Sharks" (Löschen bedrohter Haie) angeboten wird.

      Wenn die Bearbeitung abgeschlossen wurde, speichern und schließen Sie die Datei.

      Die letzte Änderung, die wir für unsere Ansichten vornehmen, wird in der Ansicht index vorgenommen, die mit unserem Controller home verknüpft ist. Sie erinnern sich vielleicht daran, dass diese Ansicht als das Stammverzeichnis der Anwendung in config/routes.rb festgelegt ist.

      Öffnen Sie diese Datei zur Bearbeitung:

      • nano app/views/home/index.html.erb

      Finden Sie die Spalte in der Zeile, die besagt Sharks are ancient (Haie sind uralt):

      ~/rails-sidekiq/app/views/home/index.html.erb

      . . .
              <div class="col-lg-6">
                  <h3>Sharks are ancient</h3>
                  <p>There is evidence to suggest that sharks lived up to 400 million years ago.
                  </p>
              </div>
          </div>
      </div>
      

      Fügen Sie den folgenden Code zur Datei hinzu:

      ~/rails-sidekiq/app/views/home/index.html.erb

      . . .
              <div class="col-lg-6">
                  <h3>Sharks are ancient and SOME are in danger</h3>
                  <p>There is evidence to suggest that sharks lived up to 400 million years ago. Without our help, some could disappear soon.</p>
                  <p><%= button_to 'Which Sharks Are in Danger?', endangered_index_path, :method => :get,  :class => "btn btn-primary btn-sm"%>
                  </p>
              </div>
          </div>
      </div>
      

      Wir haben einen Handlungsaufruf für Benutzer aufgenommen, um mehr über bedrohte Haie zu erfahren, indem wir zuerst eine starke Botschaft weitergeben und dann einen Helfer button_to hinzufügen, der eine GET-Anfrage an die Route endangered index sendet und Benutzern Zugriff auf diesen Teil der Anwendung gewährt. Von dort aus können sie Informationen über bedrohte Haie hochladen und anzeigen.

      Wenn die Bearbeitung abgeschlossen wurde, speichern und schließen Sie die Datei.

      Nachdem Sie nun Ihren Code eingegeben haben, können Sie die Anwendung starten und einige Haie hochladen!

      Schritt 5 – Starten von Sidekiq und Testen der Anwendung

      Bevor wir die Anwendung starten, müssen wir Migrationen in unserer Datenbank durchführen und Sidekiq starten, um unsere Worker zu aktivieren. Redis sollte bereits auf dem Server ausgeführt werden, aber wir können das überprüfen, um sicherzugehen. Sobald all diese Dinge eingerichtet sind, sind wir bereit, die Anwendung zu testen.

      Überprüfen Sie zunächst, ob Redis ausgeführt wird:

      Sie sollten eine Ausgabe wie die folgende sehen:

      Output

      ● redis-server.service - Advanced key-value store Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2019-11-12 20:37:13 UTC; 1 weeks 0 days ago

      Führen Sie als Nächstes Ihre Datenbankmigration durch:

      Sie können nun Sidekiq im Kontext Ihres aktuellen Projekt-Bundles starten, indem Sie den Befehl bundle exec sidekiq verwenden:

      Sie werden eine ähnliche Ausgabe wie diese sehen, die anzeigt, dass Sidekiq zur Bearbeitung von Jobs bereit ist:

      Output

      m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$b/md$$$P^' .d$$$$$$/$$$P' $$^' `"/$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ ___ | |/ _` |/ _ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|__,_|___|_|__|__, | .d$$ |_| 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Running in ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux] 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: See LICENSE and the LGPL-3.0 for licensing details. 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Booting Sidekiq 6.0.3 with redis options {:id=>"Sidekiq-server-PID-17621", :url=>nil} 2019-11-19T21:43:00.543Z pid=17621 tid=gpiqiesdl INFO: Starting processing, hit Ctrl-C to stop

      Öffnen Sie ein zweites Terminalfenster, navigieren Sie zum Verzeichnis rails-sidekiq und starten Sie Ihren Anwendungsserver.

      Wenn Sie die Anwendung lokal ausführen, verwenden Sie den folgenden Befehl:

      Wenn Sie mit einem Entwicklungsserver arbeiten, führen Sie den folgenden Befehl aus:

      • bundle exec rails s --binding=your_server_ip

      Navigieren Sie im Browser zu localhost:3000 oder http://your_server_ip:3000. Sie sehen die folgende Startseite:

      Sidekiq App Home

      Klicken Sie auf die Which Sharks Are in Danger? Schaltfläche. Da Sie keine gefährdeten Sharks hochgeladen haben, wird Ihnen die Ansicht des gefährdeten Index gezeigt:

      Ansicht des gefährdeten Index

      Klicken Sie auf Import Endangered Sharks, um die gefährdeten Sharks zu importieren. Eine Statusmeldung teilt Ihnen mit, dass die Sharks importiert wurden:

      Import beginnen

      Sie sehen auch den Beginn des Imports. Aktualisieren Sie die Seite, um die gesamte Tabelle zu sehen:

      Tabelle aktualisieren

      Dank Sidekiq ist unser umfangreiches Batch-Upload der gefährdeten Sharks gelungen, ohne den Browser zu blockieren oder die Funktionsweise anderer Anwendungen zu beeinträchtigen.

      Klicken Sie auf die Schaltfläche Home unten auf der Seite, die Sie zur Hauptseite der Anwendung zurückbringen wird:

      Sidekiq App Home

      Klicken Sie hier erneut auf Which Sharks Are in Danger? . Damit gelangen Sie nun direkt zu der Ansicht data, da Sie die Haie bereits hochgeladen haben.

      Um die Löschfunktionalität zu testen, klicken Sie auf die Schaltfläche Delete Endangered Sharks unterhalb der Tabelle. Sie sollten nun erneut zu der Hauptseite der Anwendung umgeleitet werden. Wenn Sie ein letztes Mal auf Which Sharks Are in Danger? klicken, gelangen Sie zu der Ansicht index zurück, in der Sie die Option haben, die Haie erneut hochzuladen:

      Ansicht des gefährdeten Index

      Ihre Anwendung wird nun mit Sidekiq Workers ausgeführt, die zur Bearbeitung von Jobs bereit sind und sicherstellen, dass die Benutzer eine gute Erfahrung mit Ihrer Anwendung haben.

      Zusammenfassung

      Sie haben nun eine funktionierende Rails-Anwendung mit aktiviertem Sidekiq, die es Ihnen ermöglicht, kostspielige Operationen in eine von Sidekiq verwaltete und von Redis unterstützte Job-Warteschlange auszulagern. Dadurch können Sie die Geschwindigkeit und Funktionalität Ihrer Website im Laufe der Entwicklung verbessern.

      Wenn Sie mehr über Sidekiq erfahren möchten, sind die Docs ein guter Ausgangspunkt.

      Weitere Informationen über Redis finden Sie in unserer Bibliothek der Redis Ressourcen. Sie können auch mehr über die Ausführung eines verwalteten Redis-Clusters auf DigitalOcean erfahren, indem Sie sich die Produktdokumentation ansehen.



      Source link