LU06i - Authentifizierung mit Flask-Login

Flask-Login ist eine Erweiterung für Flask, die Benutzersitzungen handhabt und es einfach macht, Funktionen wie Login, Logout und Remember Me zu implementieren. Flask-Login verwendet die Session-Funktionalität von Flask, um den angemeldeten Benutzer zu speichern.

Zuerst müssen wir Flask-Login installieren, dazu passen wir das requirements.txt an:

...
Flask-Login==0.6.3

Nach der Installation müssen wir Flask-Login in unserer Anwendung initialisieren:

from flask_login import LoginManager
 
login_manager = LoginManager()
login_manager.init_app(app)

Die Benutzerklasse muss einige spezielle Methoden erfüllen, die von Flask-Login verwendet werden: get_id(), is_authenticated, is_active und is_anonymous. Im Allgemeinen kann dies durch die Erweiterung der Benutzerklasse mit der UserMixin-Klasse von Flask-Login erreicht werden:

from flask_login import UserMixin
 
class User(UserMixin):
    def __init__(self, user_id, username, email, password):
        self.id = user_id
        self.username = username
        self.email = email
        self.password = password

Um den User in der Datenbank zu speichern, müssen wir eine entsprechende DAO-Klasse erstellen:

import sqlite3
 
class UserDao:
    def __init__(self, db_file):
        self.conn = sqlite3.connect(db_file, check_same_thread=False)
        self.cursor = self.conn.cursor()
 
    def create_user_table(self):
        self.cursor.execute('''CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, username TEXT, email TEXT, password TEXT)''')
        self.conn.commit()
 
    def add_user(self, user):
        self.cursor.execute("INSERT INTO users (username, email, password) VALUES (?, ?, ?)", (user.username, user.email, user.password))
        self.conn.commit()
 
    def get_user_by_id(self, user_id):
        self.cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
        row = self.cursor.fetchone()
        if row:
            return User(row[0], row[1], row[2], row[3])
        return None
 
    def get_user_by_username(self, username):
        self.cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
        row = self.cursor.fetchone()
        if row:
            return User(row[0], row[1], row[2], row[3])
        return None
 
    def delete_user(self, user_id):
        self.cursor.execute("DELETE FROM users WHERE id = ?", (user_id,))
        if self.cursor.rowcount > 0:
            self.conn.commit()
            return True
        return False
 
    def close(self):
        self.conn.close()

Diese DAO-Klasse bietet Methoden zum Erstellen der User-Tabelle, zum Hinzufügen von Benutzern und zum Abrufen von Benutzern anhand ihrer ID oder ihres Benutzernamens.

Die user_loader-Funktion ist ein wesentlicher Bestandteil beim Einsatz von Flask-Login. Diese Funktion ist verantwortlich für das Laden eines Benutzerobjekts basierend auf der Benutzer-ID, die in der Session gespeichert ist. Wenn ein Benutzer sich einloggt, wird seine ID in der Flask-Session gespeichert. Bei nachfolgenden Anfragen wird diese ID verwendet, um den zugehörigen Benutzer zu laden und in das current_user-Objekt zu speichern. Dadurch weiß die Anwendung während der gesamten Lebensdauer der Session, wer der aktuelle Benutzer ist.

Der @login_manager.user_loader-Dekorator markiert die Funktion, die für das Laden des Benutzers zuständig ist. Diese Funktion erhält die Benutzer-ID als Argument, führt die notwendigen Schritte zur Benutzeridentifizierung durch und gibt das entsprechende Benutzerobjekt zurück. In unserem Fall verwendet die user_loader-Funktion die get_user_by_id-Methode aus der UserDao-Klasse.

@login_manager.user_loader
def load_user(user_id):
    return user_dao.get_user_by_id(int(user_id))

Das Definieren einer user_loader-Funktion ist unerlässlich für das Funktionieren der Flask-Login-Erweiterung, da sie nicht selbstständig weiß, wie Benutzerobjekte aus der Session-ID geladen werden sollen.

Die Login-Funktion wird die get_user_by_username-Methode verwenden, um den User zu finden:

from flask_login import login_required, login_user, logout_user
 
app = Flask(__name__)
app.secret_key = 'supersecretkey' # Add a Secret-Key to the Flask App
 
 
@app.route('/login', methods=['POST'])
def login():
    data = request.get_json()
    user = user_dao.get_user_by_username(data['username'])
    if user and user.password == data['password']:
        login_user(user)
        return jsonify({'success': True}), 200
    return jsonify({'error': 'Invalid username or password'}), 401
 
@app.route('/logout')
@login_required
def logout():
    logout_user()
    return jsonify({'success': True}), 200

Um Endpunkte zu schützen, können wir den @login_required-Dekorator verwenden:

@app.route('/shoppingitems', methods=['GET'])
@login_required
def get_shopping_items():
    # Implementierung

© Kevin Maurizi

  • modul/m323/learningunits/lu06/auth.txt
  • Last modified: 2023/11/13 08:56
  • by 127.0.0.1