One place for hosting & domains

      FlaskLogin

      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

      Comment ajouter une authentification à votre application avec Flask-Login


      Introduction

      Permettre aux utilisateurs de se connecter à votre application est l’une des fonctionnalités les plus courantes que vous ajouterez à votre application web. Cet article explique comment ajouter une authentification à votre application Flask avec le paquet Flask-Login.

      Gif animé de l'application Flask et boîte de connexion

      Nous allons créer des pages d’enregistrement et de connexion qui permettent aux utilisateurs de se connecter et d’accéder à des pages protégées que les utilisateurs qui ne sont pas connectés ne peuvent pas voir. Nous prendrons les informations du modèle utilisateur et les afficherons sur nos pages protégées lorsque l’utilisateur se connectera pour simuler à quoi ressemblerait un profil.

      Nous aborderons les points suivants dans cet article :

      • Utiliser la bibliothèque Flask-Login pour la gestion des sessions
      • Utiliser l’utilitaire Flask intégré pour le hachage des mots de passe
      • Ajouter des pages protégées à notre application pour les utilisateurs connectés uniquement
      • Utiliser Flask-SQLAlchemy pour créer un modèle d’utilisateur
      • Créer des formulaires d’enregistrement et de connexion pour que nos utilisateurs puissent créer des comptes et se connecter
      • Envoyer rapidement des messages d’erreur aux utilisateurs lorsque quelque chose ne va pas
      • Utiliser les informations du compte de l’utilisateur pour les afficher sur la page de profil

      Le code source de ce projet est disponible sur GitHub.

      Conditions préalables

      Pour terminer ce tutoriel, vous aurez besoin des éléments suivants :

      Notre application utilisera le modèle d’usine de l’application Flask avec des plans. Nous aurons un modèle qui gère tout ce qui est lié à la propriété auth, et nous en aurons un autre pour nos itinéraires réguliers, qui comprennent l’index et la page de profil protégé. Dans une véritable application, vous pouvez décomposer la fonctionnalité comme vous le souhaitez, mais la solution présentée ici fonctionnera bien pour ce tutoriel.

      Voici un diagramme qui vous donnera une idée de la structure des fichiers de votre projet une fois que vous aurez terminé le tutoriel :

      .
      └── 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
      

      Au fur et à mesure que nous avancerons dans le tutoriel, nous créerons ces répertoires et ces fichiers.

      Étape 1 — Installer des paquets

      Il y a trois paquets principaux dont nous avons besoin pour notre projet :

      • Flask
      • Flask-Login : pour gérer les sessions utilisateur après authentification
      • Flask-SQLAlchemy : pour représenter le modèle d’utilisateur et l’interface avec notre base de données

      Nous utiliserons SQLite pour éviter d’avoir à installer des dépendances supplémentaires pour la base de données.

      Tout d’abord, nous allons commencer par créer le répertoire des projets :

      Ensuite, nous devons naviguer vers le répertoire du projet :

      Vous voudrez créer un environnement Python si vous n’en avez pas. Selon la façon dont Python a été installé sur votre machine, vos commandes seront similaires :

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

      Note : vous pouvez consulter le tutoriel adapté à votre environnement local pour la mise en place de venv.

      Exécutez les commandes suivantes depuis votre environnement virtuel pour installer les paquets nécessaires :

      • pip install flask flask-sqlalchemy flask-login

      Maintenant que vous avez installé les paquets, vous êtes prêt à créer le fichier principal de l’application.

      Étape 2 — Création du dossier d’application principale

      Commençons par créer un répertoire project :

      Le premier dossier sur lequel nous travaillerons sera le fichier __init__.py pour notre projet :

      Ce fichier aura pour fonction de créer notre app, qui initialisera la base de données et enregistrera nos plans. Pour l’instant, cela ne fera pas grand-chose, mais ce sera nécessaire pour le reste de notre application. Nous devons initialiser SQLAlchemy, définir quelques valeurs de configuration et enregistrer nos plans ici.

      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
      

      Maintenant que nous avons le fichier principal de l’application, nous pouvons commencer à ajouter des itinéraires.

      Étape 3 — Ajouter des itinéraires

      Pour nos itinéraires, nous utiliserons deux plans. Pour notre plan principal, nous aurons une page d’accueil (/) et la page de profil (/profile) pour après s’être connecté. Si l’utilisateur tente d’accéder à la page de profil sans être connecté, il sera envoyé sur l’intinéraire de connexion.

      Pour notre plan d’authentification, nous aurons des itinéraires pour récupérer à la fois la page de connexion (/login) et la page d’inscription (/sign-up). Nous aurons également des itinéraires pour traiter les demandes POST provenant de ces deux itinéraires. Enfin, nous aurons un itinéraire de déconnexion (/logout) pour déconnecter un utilisateur actif.

      Pour l’instant, nous allons définir le login, signup, et logout avec des retours simples. Nous les réexaminerons à une étape ultérieure et les mettrons à jour avec la fonctionnalité souhaitée.

      Tout d’abord, créez main.py pour votre 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'
      

      Ensuite, créez auth.py pour votre 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'
      

      Dans un terminal, vous pouvez définir les valeurs FLASK_APP et FLASK_DEBUG :

      • export FLASK_APP=project
      • export FLASK_DEBUG=1

      La variable d’environnement FLASK_APP indique à Flask comment charger l’application. Elle doit indiquer où create_app est situé. Pour nos besoins, nous indiquerons le répertoire des projets.

      La variable d’environnement FLASK_DEBUG est activée en lui donnant la valeur 1, ce qui activera un débogueur qui affichera les erreurs de l’application dans le navigateur.

      Assurez-vous que vous êtes dans le répertoire flask_auth_app et puis exécutez le projet :

      Maintenant, dans un navigateur web, vous devriez être en mesure de naviguer vers les cinq URL possibles et voir le texte renvoyé qui a été défini dans auth.py et main.py.

      Par exemple, visiter localhost:5000/profile affiche : Profile :

      Capture d'écran du projet au port 5000 de localhost dans le navigateur

      Maintenant que nous avons vérifié que nos itinéraires se comportent comme prévu, nous pouvons passer à la création de modèles.

      Étape 4 — Créer des modèles

      Allons de l’avant et créons les modèles qui sont utilisés dans notre application. C’est la première étape avant que nous puissions mettre en œuvre la fonctionnalité de connexion proprement dite. Notre application utilisera quatre modèles :

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

      Nous aurons également un modèle de base qui aura un code commun à chacune des pages. Dans ce cas, le modèle de base sera doté de liens de navigation et de la disposition générale de la page. Créons-les maintenant.

      Tout d’abord, créez un répertoire de modèles sous le répertoire de project :

      • mkdir -p project/templates

      Ensuite, créez base.html :

      • nano project/templates/base.html

      Ensuite, ajoutez le code suivant au fichier base.html :

      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>
      

      Ce code créera une série de liens de menu vers chaque page de l’application et une zone où le contenu apparaîtra .

      Remarque : En arrière-plan, nous utilisons Bulma pour s’occuper du style et de la mise en page. Pour une plongée plus approfondie dans Bulma, pensez à lire la documentation officielle de Bulma.

      Ensuite, créez templates/index.html:

      • nano project/templates/index.html

      Ajoutez le code suivant au fichier nouvellement créé pour ajouter du contenu à la page :

      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 %}
      

      Ce code permettra de créer une page d’index de base avec un titre et un sous-titre.

      Ensuite, créez templates/login.html :

      • nano project/templates/login.html

      Ce code génère une page de connexion avec des champs pour Email et Password. Il y a également une case à cocher pour « se souvenir » d’une session connectée.

      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 %}
      

      Ensuite, créez templates/signup.html :

      • nano project/templates/signup.html

      Ajoutez le code suivant pour créer une page d’inscription avec des champs pour email, name, et password :

      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 %}
      

      Ensuite, créez templates/profile.html :

      • nano project/templates/profile.html

      Ajoutez ce code pour créer une page simple avec un titre codé en dur pour accueillir Anthony:

      project/templates/profile.html

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

      Plus tard, nous ajouterons du code pour saluer dynamiquement tout utilisateur.

      Une fois que vous avez ajouté les modèles, nous pouvons mettre à jour les déclarations de retour dans chacun des itinéraires ; nous devons renvoyer les modèles au lieu du texte.

      Ensuite, mettez à jour main.py en modifiant la ligne d’importation et les itinéraires pour index et 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')
      

      Vous allez maintenant mettre à jour auth.py en modifiant la ligne d’importation et les itinéraires pour login et 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')
      

      Une fois que vous avez effectué ces changements, voici à quoi ressemble la page d’inscription si vous naviguez vers /signup :

      Page d'inscription à /signup

      Vous devriez pouvoir voir également les pages pour /, /login et /profile.

      Nous laisserons /logout seul pour l’instant car il n’affichera pas de modèle quand il sera terminé.

      Étape 5 — Créer des modèles d’utilisateurs

      Notre modèle d’utilisateur représente ce que cela signifie pour notre app d’avoir un utilisateur. Nous aurons des champs pour une adresse électronique, un mot de passe et un nom. Dans votre application, vous pouvez décider que vous souhaitez que beaucoup plus d’informations soient stockées par utilisateur. Vous pouvez ajouter des éléments tels que l’anniversaire, la photo de profil, la localisation ou toute autre préférence de l’utilisateur.

      Les modèles créés dans Flask-SQLAlchemy sont représentés par des classes qui sont ensuite traduites en tables dans une base de données. Les attributs de ces classes se transforment alors en colonnes pour ces tables.

      Allons de l’avant et créons ce modèle d’utilisateur :

      Ce code crée un modèle d’utilisateur avec des colonnes pour un id, email, password et un 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))
      

      Maintenant que vous avez créé un modèle d’utilisateur, vous pouvez passer à la configuration de votre base de données.

      Étape 6 — Configurer la base de données

      Comme indiqué dans les conditions préalables, nous utiliserons une base de données SQLite. Nous pourrions créer nous-mêmes une base de données SQLite, mais laissons Flask-SQLAlchemy le faire pour nous. Nous avons déjà le chemin de la base de données spécifié dans le fichier__init__.py,il suffit donc de dire à Flask-SQLAlchemy de créer la base de données dans le REPL Python.

      Si vous arrêtez votre application et ouvrez un REPL en Python, nous pouvons créer la base de données en utilisant la méthode create_all sur l’objet db. Assurez-vous que vous êtes toujours dans l’environnement virtuel et dans le répertoire flask_auth_app.

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

      Note : Si l’utilisation de l’interpréteur Python est nouvelle pour vous, vous pouvez consulter la documentation officielle.

      Vous allez maintenant voir un fichier db.sqlite dans le répertoire de votre projet. Cette base de données contiendra notre table d’utilisateurs.

      Étape 7 — Mettre en place la fonction d’autorisation

      Pour notre fonction d’inscription, nous allons prendre les données que l’utilisateur tape dans le formulaire et les ajouter à notre base de données. Avant de les ajouter, nous devons nous assurer que l’utilisateur n’existe pas déjà dans la base de données. Si ce n’est pas le cas, nous devons nous assurer que nous avons bien haché le mot de passe avant de le placer dans la base de données, car nous ne voulons pas que nos mots de passe soient stockés en clair.

      Commençons par ajouter une deuxième fonction pour traiter les données du formulaire POST. Dans cette fonction, nous allons d’abord recueillir les données transmises par l’utilisateur.

      Créez la fonction et ajoutez une redirection vers le bas. Cela permettra à l’utilisateur de faire l’expérience d’une inscription réussie et d’être dirigé vers la page de connexion.

      Mettez à jour auth.py en modifiant la ligne d’importation et en mettant en œuvre 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'))
      

      Maintenant, ajoutons le reste du code nécessaire à l’inscription d’un utilisateur.

      Pour commencer, nous devrons utiliser l’objet de demande pour obtenir les données du formulaire.

      Continuez à mettre à jour auth.py en ajoutant des importations et en mettant en œuvre signup_post:

      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'))
      

      Remarque : Le stockage des mots de passe en clair est considéré comme une mauvaise pratique de sécurité. Vous voudrez généralement utiliser un algorithme de hachage complexe et un sel de mot de passe pour assurer la sécurité des mots de passe.

      Étape 8 — Tester la méthode d’inscription

      Maintenant que la méthode d’inscription est terminée, nous devrions être en mesure de créer un nouvel utilisateur. Utilisez le formulaire pour créer un utilisateur.

      Il y a deux façons de vérifier si l’inscription a fonctionné : vous pouvez utiliser un visualiseur de base de données pour regarder la ligne qui a été ajoutée à votre table, ou vous pouvez essayer de vous inscrire à nouveau avec la même adresse électronique, et si vous obtenez une erreur, vous savez que le premier courriel a été enregistré correctement. Adoptons donc cette approche.

      Nous pouvons ajouter un code pour faire savoir à l’utilisateur que le courriel existe déjà et lui dire de se rendre à la page de connexion. En appelant la fonction flash, nous enverrons un message à la demande suivante, qui dans ce cas, est la redirection. La page sur laquelle nous arrivons aura alors accès à ce message dans le modèle.

      D’abord, nous ajoutons le flash avant de rediriger vers notre page d’enregistrement.

      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'))
      

      Pour obtenir le message clignotant dans le modèle, nous pouvons ajouter ce code au-dessus du formulaire. Le message s’affichera alors directement au-dessus du formulaire.

      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">
      

      Boîte d'inscription affichant un message qui indique que l'adresse électronique existe déjà. Allez à la page de login dans une boîte rose foncé

      Étape 9 — Ajouter la méthode de connexion

      La méthode de connexion est similaire à la fonction d’inscription en ce sens que nous prenons les informations de l’utilisateur et en faisons quelque chose. Dans ce cas, nous comparerons l’adresse électronique saisie pour voir si elle se trouve dans la base de données. Si c’est le cas, nous testerons le mot de passe fourni par l’utilisateur en hachant le mot de passe que l’utilisateur nous a communiqué et en le comparant au mot de passe haché dans la base de données. Nous savons que l’utilisateur a saisi le bon mot de passe lorsque les deux mots de passe hachés correspondent.

      Une fois que l’utilisateur a passé le contrôle du mot de passe, nous savons qu’il possède les bonnes références et nous pouvons le connecter en utilisant Flask-Login. En appelant login_user, Flask-Login créera une session pour cet utilisateur qui persistera tant que l’utilisateur restera connecté, ce qui lui permettra de voir les pages protégées.

      Nous pouvons commencer par un nouveau mode de traitement des données POSTed. Nous redirigerons vers la page de profil lorsque l’utilisateur se connectera avec succès :

      project/auth.py

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

      Maintenant, nous devons vérifier si l’utilisateur possède les bons identifiants

      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'))
      

      Ajoutons le bloc dans le modèle pour que l’utilisateur puisse voir le message clignotant. Comme pour le formulaire d’inscription, ajoutons le message d’erreur potentiel directement au-dessus du formulaire :

      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">
      

      Nous avons maintenant la possibilité de dire qu’un utilisateur a été connecté avec succès, mais il n’y a rien pour connecter l’utilisateur. C’est là que nous introduisons Flask-Login pour gérer les sessions des utilisateurs.

      Avant de commencer, nous avons besoin de quelques éléments pour que Flask-Login fonctionne. Commencez par ajouter le UserMixin à votre modèle User. Le UserMixin ajoutera les attributs de Flask-Login au modèle afin que Flask-Login puisse travailler avec lui.

      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))
      

      Ensuite, nous devons spécifier notre chargeur d’utilisateurs. Un chargeur d’utilisateur indique à Flask-Login comment trouver un utilisateur spécifique à partir de son identifiant stocké dans son cookie de session. Nous pouvons l’ajouter dans notre create_app ainsi que le code init du Flask-Login :

      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))
      

      Enfin, nous pouvons ajouter le login_user juste avant de rediriger vers la page de profil pour créer la session :

      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'))
      

      Avec la configuration de Flask-Login, nous pouvons utiliser l’itinéraire /login. Lorsque tout est en place, vous verrez la page de profil.

      Page de profil avec « Welcome, Anthony! »

      Étape 10 — Protéger les pages

      Si votre nom n’est pas aussi Anthony, alors vous verrez que votre nom est faux. Ce que nous voulons, c’est que le profil affiche le nom dans la base de données. Nous devons donc d’abord protéger la page et ensuite accéder aux données de l’utilisateur pour obtenir le nom.

      Pour protéger une page lors de l’utilisation de Flask-Login, nous ajoutons le décorateur @login_required entre l’itinéraire et la fonction. Cela empêchera un utilisateur qui n’est pas connecté de voir l’itinéraire. Si l’utilisateur n’est pas connecté, il sera redirigé vers la page de connexion, selon la configuration du Flask-Login.

      Avec les itinéraires qui sont décorés avec le décorateur @login_required, nous avons alors la possibilité d’utiliser l’objet current_user à l’intérieur de la fonction. Ce current_user représente l’utilisateur de la base de données, et nous pouvons accéder à tous les attributs de cet utilisateur avec la notation par points. Par exemple, current_user.email, current_user.password, et current_user.name, et current_user.id renverront les valeurs réelles stockées dans la base de données pour l’utilisateur connecté.

      Utilisons le nom de l’utilisateur actuel et envoyons-le au modèle. Nous utiliserons alors ce nom et afficherons sa valeur.

      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)
      

      Ensuite, dans le fichier profile.html, mettez à jour la page pour afficher la valeur name :

      project/templates/profile.html

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

      Une fois que nous nous rendons sur notre page de profil, nous voyons alors que le nom de l’utilisateur apparaît.

      Page d'accueil de l'utilisateur avec le nom de l'utilisateur actuellement connecté

      La dernière chose que nous pouvons faire est de mettre à jour la vue de déconnexion. Nous pouvons appeler le logout_user dans un itinéraire de déconnexion. Nous avons le décorateur @login_required parce qu’il n’est pas logique de déconnecter un utilisateur qui n’est pas connecté au départ.

      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'))
      

      Lorsque nous nous déconnectons et que nous essayons de consulter à nouveau la page de profil, nous voyons apparaître un message d’erreur. C’est parce que Flask-Login fait clignoter un message pour nous lorsque l’utilisateur n’est pas autorisé à accéder à une page.

      Page de connexion avec un message indiquant que l'utilisateur doit se connecter pour accéder à la page

      Une dernière chose que nous pouvons faire est de mettre des déclarations if dans les modèles pour afficher uniquement les liens pertinents pour l’utilisateur. Ainsi, avant que l’utilisateur ne se connecte, il aura la possibilité de se connecter ou de s’inscrire. Une fois que l’on se connecte, on peut aller sur son profil ou se déconnecter :

      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>
      

      Page d'accueil avec la navigation « Home, Login, and Sign Up» en haut de l'écran

      Grâce à cela, vous avez réussi à construire votre application avec authentification.

      Conclusion

      Nous avons utilisé Flask-Login et Flask-SQLAlchemy afin de créer un système de connexion pour notre app. Nous avons abordé la manière d’authentifier un utilisateur en créant d’abord un modèle d’utilisateur et en stockant les informations sur l’utilisateur. Ensuite, nous avons dû vérifier que le mot de passe de l’utilisateur était correct en hachant le mot de passe du formulaire et en le comparant à celui stocké dans la base de données. Enfin, nous avons ajouté l’autorisation à notre app en utilisant le décorateur @login_required sur une page de profil afin que seuls les utilisateurs connectés puissent voir cette page.

      Ce que nous avons créé dans ce tutoriel sera suffisant pour les petites applications, mais si vous souhaitez avoir plus de fonctionnalités dès le début, vous pouvez envisager d’utiliser les bibliothèques Flask-User ou Flask-Security qui sont toutes deux construites sur la bibliothèque Flask-Login.



      Source link

      Como adicionar uma autenticação ao seu aplicativo com o Flask-Login


      Introdução

      Permitir que usuários façam login em seu aplicativo é um dos recursos mais comuns a ser adicionado ao seu aplicativo Web. Este artigo irá abordar como adicionar uma autenticação ao seu aplicativo Flask com o pacote Flask-Login.

      Gif animado do aplicativo Flask e caixa de login

      Construiremos algumas páginas de inscrição e login que permitem que os usuários façam login e acessem páginas protegidas que usuários não autenticados são incapazes de visualizar. Coletaremos informações do modelo de usuário e as exibiremos em nossas páginas protegidas quando o usuário fizer login, de forma a simular como seria um perfil.

      Iremos abordar os seguintes assuntes neste artigo:

      • Como usar a biblioteca Flask-Login para o gerenciamento de sessão
      • Como usar o utilitário integrado do Flask para o hash de senhas
      • Como adicionar páginas protegidas ao nosso aplicativo acessíveis somente por usuários autenticados
      • Como usar o Flask-SQLAlchemy para criar um modelo de usuário
      • Como criar formulários de inscrição e login para que nossos usuários criem contas e façam login
      • Como exibir mensagens de erro aos usuários quando algo der errado
      • Como usar informações da conta do usuário para exibi-las na página do perfil

      O código fonte para este projeto está disponível no GitHub.

      Pré-requisitos

      Para concluir este tutorial, você precisará do seguinte:

      Nosso aplicativo irá utilizar os padrões de fábrica do aplicativo Flask com blueprints. Teremos um blueprint que processa tudo que está relacionado à autenticação e outro para nossas rotas regulares, que incluem o índice e a página de perfil protegida. Em um aplicativo real, é possível desmembrar as funcionalidades da maneira que achar melhor, mas a solução abordada aqui irá funcionar bem para este tutorial.

      Aqui está um diagrama para entendermos melhor como ficará a estrutura de arquivos do seu projeto após completar o tutorial:

      .
      └── 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
      

      À medida que avançarmos neste tutorial, iremos criar esses diretórios e arquivos.

      Passo 1 — Instalando os pacotes

      Existem três pacotes principais que precisamos para o nosso projeto:

      • Flask
      • Flask-Login: para processar as sessões de usuário após a autenticação
      • Flask-SQLAlchemy: para representar o modelo de usuário e interagir com nosso banco de dados

      Iremos utilizar o SQLite para evitar a instalação de dependências extras para o banco de dados.

      Primeiro, começaremos criando o diretório de projeto:

      Em seguida, precisamos navegar até o diretório de projeto:

      Crie um ambiente Python caso não tenha um. Dependendo da forma como o Python foi instalado em sua máquina, seus comandos serão semelhantes a:

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

      Nota: consulte o tutorial relevante ao seu ambiente de trabalho para configurar o venv.

      Execute os comandos a seguir a partir do seu ambiente virtual para instalar os pacotes necessários:

      • pip install flask flask-sqlalchemy flask-login

      Agora que você instalou os pacotes, tudo está pronto para a criação do arquivo principal do aplicativo.

      Passo 2 — Criando o arquivo principal do aplicativo

      Vamos começar criando um diretório project:

      O primeiro arquivo no qual trabalharemos será o arquivo __init__.py para o nosso projeto:

      Esse arquivo será responsável pela criação do nosso aplicativo, inicializando o banco de dados e registrando nossos blueprints. Neste momento, aparentemente nada irá mudar. No entanto, isso será necessário para o resto do nosso aplicativo. Precisamos inicializar o SQLAlachemy, definir alguns valores de configuração e registrar nossos blueprints aqui.

      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
      

      Agora que temos o arquivo principal do aplicativo, podemos começar a adicionar nossas rotas.

      Passo 3 — Adicionando rotas

      Para nossas rotas, iremos utilizar dois blueprints. Para o nosso blueprint principal, teremos uma página inicial (/) e uma página de perfil (/profile) para depois da sessão ser iniciada. Se o usuário tentar acessar a página de perfil sem estar autenticado, ele será enviado para a rota de login.

      Para o nosso blueprint de autenticação, teremos rotas para recuperar tanto a página de login (/login) quanto a página de inscrição (/sign-up). Também teremos rotas para lidar com as solicitações POST de ambas as rotas. Por fim, teremos uma rota de logoff (/logout) para efetuar o logoff de um usário ativo.

      Por enquanto, iremos definir login, signup e logout com devoluções simples. Iremos revisitá-los em um passo posterior e atualizá-los com a funcionalidade desejada.

      Primeiro, crie o main.py para o seu 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'
      

      Em seguida, crie o auth.py para o seu 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'
      

      Em um terminal, defina os valores FLASK_APP e FLASK_DEBUG:

      • export FLASK_APP=project
      • export FLASK_DEBUG=1

      A variável de ambiente FLASK_APP instrui o Flask sobre como carregar o aplicativo. Ela deve apontar para o local onde o create_app está localizado. Para o nosso caso, iremos apontar para o diretório project.

      A variável de ambiente FLASK_DEBUG é habilitada quando definida em 1. Isso irá habilitar um depurador que exibirá erros do aplicativo no navegador.

      Certifique-se de estar no diretório flask_auth_app e então execute o projeto:

      Agora, em um navegador, deve ser possível navegar até as cinco URLs possíveis e ver o texto retornado que foi definido em auth.py e main.py.

      Por exemplo, visitar o localhost:5000/profile exibe Profile:

      Captura de tela do projeto em localhost porta 5000 no navegador

      Agora que verificamos que nossas rotas estão se comportando conforme esperado, podemos seguir em frente para a criação de modelos.

      Passo 4 — Criando modelos

      Vamos continuar e criar os modelos usados em nosso aplicativo. Este é o primeiro passo antes de podermos implementar de fato a funcionalidade de login. Nosso aplicativo irá utilizar quatro modelos:

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

      Além disso, teremos um modelo base que terá partes de código comuns a cada uma das páginas. Neste caso, o modelo base terá links de navegação e o layout geral da página. Vamos criá-los agora.

      Primeiro, crie um diretório templates no seu diretório project:

      • mkdir -p project/templates

      Em seguida, crie o base.html:

      • nano project/templates/base.html

      Depois, adicione o código a seguir ao arquivo base.html:

      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>
      

      Esse código irá criar uma série de links de menu para cada página do aplicativo e uma área onde o conteúdo irá aparecer.

      Nota: nos bastidores, estamos usando o Bulma para lidar com a estilização e o layout. Para entender mais sobre o Bulma, leia a documentação oficial do Bulma.

      Em seguida, crie o templates/index.html:

      • nano project/templates/index.html

      Adicione o código a seguir ao arquivo recém-criado para adicionar conteúdo à página:

      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 %}
      

      Esse código irá criar um uma página básica de índice com um título e um subtítulo.

      Em seguida, crie o templates/login.html:

      • nano project/templates/login.html

      Esse código gera uma página de login com campos para E-mail e Senha. Há também uma caixa de seleção para “lembrar” uma sessão iniciada.

      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 %}
      

      Em seguida, crie o templates/signup.html:

      • nano project/templates/signup.html

      Adicione o código a seguir para criar uma página de inscrição com campos para e-mail, nome e senha:

      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 %}
      

      Em seguida, crie o templates/profile.html:

      • nano project/templates/profile.html

      Adicione este código para criar uma página simples com um título embutido em código para dar boas vindas ao Anthony:

      project/templates/profile.html

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

      Posteriormente, iremos adicionar um código para saudar dinamicamente qualquer usuário.

      Assim que os modelos forem adicionados, podemos atualizar as declarações de retorno em cada uma de nossas rotas para que retornem os modelos ao invés do texto.

      Em seguida, atualize o main.py alterando a linha de importação e as rotas para o index e 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')
      

      Agora, você irá atualizar o auth.py modificando a linha de importação e rotas para login e 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')
      

      Assim que as alterações forem feitas, a página de inscrição ficará desta forma, caso navegue até /sign-up:

      Página de inscrição em /signup

      Também deve ser possível ver as páginas para /, /login e /profile.

      Não iremos alterar /logout por enquanto, pois ela não irá exibir um modelo quando for finalizada.

      Passo 5 — Criando modelos de usuário

      Nosso modelo de usuário representa o que significa para o nosso aplicativo ter um usuário. Teremos campos para um endereço de e-mail, senha e nome. Em seu aplicativo, fique a vontade para decidir se quer que mais informações sejam armazenadas por usuário. É possível adicionar coisas como aniversário, imagem de perfil, localização ou qualquer preferência do usuário.

      Os modelos criados no Flask-SQLAlchemy são representados por classes que então se traduzem em tabelas em um banco de dados. Os atributos dessas classes transformam-se então em colunas para essas tabelas.

      Vamos continuar e criar o modelo de usuário:

      Este código cria um modelo de usuário com colunas para um id, email, password e 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))
      

      Agora que um modelo de usuário foi criado, continue para a configuração do seu banco de dados.

      Passo 6 — Configurando o banco de dados

      Como mencionado nos pré-requisitos, iremos utilizar um banco de dados SQLite. Poderíamos criar um banco de dados SQLite por conta própria, mas vamos deixar o Flask-SQLAlchemy fazer isso por nós. Nós já temos o caminho do banco de dados especificado no arquivo __init__.py. Portanto, precisamos apenas dizer ao Flask-SQLAlchemy para criar o banco de dados no REPL do Python.

      Se você parar o aplicativo e abrir um REPL do Python, seremos capazes de criar o banco de dados usando o método create_all no objeto db. Certifique-se de que você ainda esteja no ambiente virtual e no diretório flask_auth_app.

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

      Nota: caso usar o interpretador do Python seja algo novo para você, consulte a documentação oficial.

      Agora, você verá um arquivo db.sqlite em seu diretório de projeto. Esse banco de dados terá a nossa tabela de usuário em seu interior.

      Passo 7 — Configurando a função de autorização

      Para a nossa função de inscrição, enviaremos os dados que o usuário digita no formulário ao nosso banco de dados. Antes de adicioná-la, precisamos garantir que o usuário não exista no banco de dados. Se ele não existir, então precisamos nos certificar que a senha passará pelo hash antes de colocá-la no banco de dados, pois não queremos que nossas senhas sejam armazenadas em texto simples.

      Vamos começar adicionando uma segunda função para lidar com os dados do formulário POST. Nesta função, coletaremos dados passados pelo usuário primeiro.

      Crie a função e adicione um redirecionamento no final. Isso proporcionará uma experiência de usuário de uma inscrição bem-sucedida e direcionamento à Página de login.

      Atualize o auth.py alterando a linha de importação e implementando o 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'))
      

      Agora, vamos adicionar o resto do código necessário para a inscrição de um usuário.

      Para começar, será necessário usar o objeto de solicitação para obter os dados do formulário.

      Continue atualizando o auth.py adicionando as importações e implementando o signup_post:

      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'))
      

      Nota: armazenar senhas em texto simples é considerada uma prática de segurança ruim. De maneira geral, é vantajoso utilizar um algoritmo de hash complexo e um valor de sal de senha para manter as senhas em segurança.

      Passo 8 — Testando o método de inscrição

      Agora que o método de inscrição está finalizado, devemos ser capazes de criar um novo usuário. Use o formulário para criar um usuário.

      Existem duas maneiras de verificar se a inscrição foi bem-sucedida: usando o visualizador do banco de dados para observar a linha que foi adicionada à sua tabela, ou tentando inscrever-se com o mesmo e-mail novamente e, caso receba um erro, saberá que o primeiro e-mail foi salvo corretamente. Portanto, vamos tomar esta segunda abordagem.

      Podemos adicionar um código para informar ao usuário que o e-mail já existe e pedir para que vá à página de login. Ao chamar a função flash, iremos enviar uma mensagem para a próxima solicitação, que, neste caso, é o redirecionamento. Dessa forma, a página em que chegarmos terá acesso a essa mensagem no modelo.

      Primeiro, adicionamos o flash antes de redirecionarmos o processo de volta à nossa página de inscrição.

      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'))
      

      Para o recebimento da mensagem de flash no modelo, podemos adicionar este código acima do formulário. Isso fará com que a mensagem seja exibida diretamente acima do formulário.

      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">
      

      Caixa de inscrição exibindo uma mensagem de que o

      Passo 9 — Adicionando o método de login

      O método de login é semelhante à função de inscrição, já que também iremos pegar informações do usuário para fazer algo com elas. Neste caso, iremos analisar o endereço de e-mail inserido para checar se ele está presente no banco de dados. Caso esteja, iremos testar a senha fornecida pelo usuário utilizando o hash na senha passada pelo usuário e comparando-a com a senha já com hash no banco de dados. Sabemos que o usuário digitou a senha correta quando ambas as senhas com hash correspondem.

      Assim que o usuário passar pela checagem de senha, sabemos que ele possui as credenciais corretas e podemos autenticá-los usando o Flask-Login. Ao chamar o login_user, o Flask-Login irá criar uma sessão para aquele usuário que irá persistir enquanto o usuário permanecer conectado. Isso permitirá que o usuário visualize páginas protegidas.

      Podemos começar com uma nova rota para o manuseio dos dados em POST. Redirecionaremos o usuário para a página de perfil quando o login for realizado com sucesso:

      project/auth.py

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

      Agora, é necessário verificar se o usuário possui as credenciais corretas:

      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'))
      

      Vamos adicionar o bloco de código no modelo para que o usuário possa ver a mensagem em flash. Assim como no formulário de inscrição, vamos adicionar a mensagem de erro em potencial diretamente acima do formulário:

      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">
      

      Agora, somos capazes de dizer que um usuário foi conectado com sucesso, mas não há nada para fazer o login do usuário. É aqui onde trazemos o Flask-Login para o gerenciamento de sessões de usuário.

      Antes de iniciarmos, precisamos de algumas coisas para que o Flask-Login funcione. Comece adicionando o UserMixin ao seu Modelo de usuário. O UserMixin irá adicionar atributos do Flask-Login ao modelo para que o Flask-Login seja capaz de trabalhar com ele.

      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))
      

      Em seguida, é necessário especificar nosso carregador de usuário. Um carregador de usuário informa ao Flask-Login como encontrar um usuário específico a partir do ID armazenado em seu cookie de sessão. Podemos adicionar isso em nossa função create_app, juntamente com o código init para o Flask-Login:

      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))
      

      Por fim, adicionamos a função login_user um pouco antes de redirecionarmos o usuário para a página de perfil para criar a sessão:

      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'))
      

      Com o Flask-Login configurado, podemos usar a rota /login. Quando tudo estiver no lugar, você verá a página de perfil.

      Página de perfil com

      Passo 10 — Protegendo as páginas

      Se o seu nome não é Anthony, então verá que a mensagem está errada. O que queremos é que o perfil exiba o nome presente no banco de dados. Portanto, primeiro, é necessário proteger a página e então acessar os dados do usuário para obter o seu nome.

      Para proteger uma página ao usar o Flask-Login, adicionamos o decorador @login_requried entre a rota e a função. Isso impede que um usuário que não esteja conectado veja a rota. Se o usuário não estiver conectado, ele será redirecionado para a página de login, conforme a configuração do Flask-Login.

      Com as rotas decoradas com o decorador @login_required, somos capazes de usar o objeto current_user dentro da função. O current_user representa o usuário do banco de dados e podemos acessar todos os atributos desse usuário com uma notação de ponto. Por exemplo, current_user.email, current_user.password, current_user.name e current_user.id irão retornar os valores reais armazenados no banco de dados para o usuário conectado.

      Vamos usar o nome do usuário atual e enviá-lo ao modelo. Em seguida, usaremos esse nome e exibiremos seu valor.

      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)
      

      Depois disso, no arquivo profile.html, atualize a página para exibir o valor name:

      project/templates/profile.html

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

      Ao acessarmos nossa página de perfil, vemos agora que o nome do usuário aparece.

      Página de boas-vindas com o nome do usuário atualmente conectado

      A última coisa que podemos fazer é atualizar a visualização de logoff. Podemos chamar a função logout_user em uma rota para o logoff. Adicionamos o decorador @login_required porque não faz sentido fazer logoff de um usuário que não esteja conectado em primeiro lugar.

      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'))
      

      Depois de fazer o logoff, se tentarmos visualizar a página de perfil novamente, vemos que uma mensagem de erro aparece. Isso ocorre porque o Flask-Login exibe uma mensagem quando o usuário não é autorizado a acessar uma página.

      Página de login com uma mensagem mostrando que o usuário deve fazer login para acessar a página

      Uma última coisa que podemos fazer é colocar declarações if nos modelos para que apenas os links relevantes ao usuário sejam exibidos. Assim, antes do usuário fazer login, haverá a opção de fazer login ou se inscrever. Após ter feito o login, é possível ir ao perfil ou fazer logoff:

      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>
      

      Página inicial com as opções Home, Login e Sign Up no topo da tela

      Com isso, você terminou de construir seu aplicativo de autenticação com sucesso.

      Conclusão

      Utilizamos neste tutorial o Flask-Login e o Flask-SQLAlchemy para construir um sistema de login para o nosso aplicativo e abordamos como autenticar um usuário. Primeiro, criamos um modelo de usuário e armazenamos suas informações. Em seguida, foi necessário verificar se a senha do usuário estava correta utilizando o hash na senha do formulário e comparando-a com a armazenada no banco de dados. Por fim, adicionamos a autorização ao nosso aplicativo usando o decorador @login_required em uma página de perfil para que apenas usuários conectados possam ver essa página.

      O que criamos neste tutorial será o suficiente para aplicativos menores, mas se você quiser ter mais funcionalidades logo no início, considere usar as bibliotecas Flask-User ou Flask-Security, que são desenvolvidas com base na biblioteca Flask-Login.



      Source link