Einführung
Die Implementierung einer sicheren Authentifizierung ist ein entscheidender Aspekt beim Aufbau robuster Python-Client-Server-Systeme. Dieses Tutorial führt Sie durch den Prozess der Implementierung von Authentifizierung in Ihren Python-Anwendungen, beginnend mit der grundlegenden Benutzername- und Passwort-Authentifizierung und übergehend zu tokenbasierten Methoden. Am Ende dieses Labors werden Sie verstehen, wie Sie Ihre Python-Anwendungen mit geeigneten Authentifizierungsmechanismen sichern können.
Grundlagen der Authentifizierung verstehen und Ihre Umgebung einrichten
Authentifizierung ist der Prozess der Überprüfung der Identität eines Benutzers oder Systems, bevor der Zugriff auf geschützte Ressourcen gewährt wird. In Client-Server-Systemen stellt eine ordnungsgemäße Authentifizierung sicher, dass nur autorisierte Benutzer auf sensible Daten zugreifen oder bestimmte Operationen ausführen können.
Einrichten Ihrer Umgebung
Beginnen wir mit der Einrichtung unserer Arbeitsumgebung. Erstellen Sie zunächst ein neues Verzeichnis für unser Projekt:
mkdir -p ~/project/auth_demo
cd ~/project/auth_demo
Als Nächstes müssen wir die notwendigen Python-Pakete installieren, die wir in diesem Labor verwenden werden:
pip install flask flask-login requests
Sie sollten eine Ausgabe ähnlich dieser sehen:
Collecting flask
Downloading Flask-2.2.3-py3-none-any.whl (101 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 101.8/101.8 KB 6.2 MB/s eta 0:00:00
Collecting flask-login
Downloading Flask_Login-0.6.2-py3-none-any.whl (17 kB)
Collecting requests
Downloading requests-2.29.0-py3-none-any.whl (62 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.5/62.5 KB 5.5 MB/s eta 0:00:00
...
Successfully installed flask-2.2.3 flask-login-0.6.2 requests-2.29.0 ...
Authentifizierungskonzepte
Bevor wir uns der Implementierung zuwenden, wollen wir die grundlegenden Authentifizierungskonzepte verstehen:
Benutzername- und Passwort-Authentifizierung: Die gebräuchlichste Form, bei der Benutzer Anmeldeinformationen zur Überprüfung ihrer Identität angeben.
Tokenbasierte Authentifizierung: Nach erfolgreicher Anmeldung generiert der Server ein Token für den Client, das in nachfolgenden Anfragen verwendet werden kann, wodurch die Notwendigkeit entfällt, jedes Mal Anmeldeinformationen zu senden.
Sitzungsbasierte Authentifizierung: Der Server speichert Sitzungsinformationen nach einer erfolgreichen Anmeldung und stellt dem Client eine Sitzungs-ID zur Verfügung.
Lassen Sie uns einen grundlegenden Authentifizierungsablauf visualisieren:
Client Server
| |
|--- Login Request (credentials) ---->|
| |--- Verify Credentials
| |
|<---- Authentication Response -------|
| |
|--- Subsequent Requests (with auth) >|
| |--- Verify Auth
| |
|<---- Protected Resource Response ---|
Nachdem wir nun die Grundlagen verstanden und unsere Umgebung eingerichtet haben, erstellen wir eine einfache Dateistruktur für unser Projekt:
touch ~/project/auth_demo/server.py
touch ~/project/auth_demo/client.py
Im nächsten Schritt implementieren wir ein einfaches Benutzername- und Passwort-Authentifizierungssystem mit Flask auf der Serverseite und einem Python-Client, um sich damit zu authentifizieren.
Implementierung der grundlegenden Benutzername- und Passwort-Authentifizierung
In diesem Schritt implementieren wir ein grundlegendes Authentifizierungssystem, das Benutzernamen und Passwörter verwendet. Wir erstellen:
- Einen Flask-Server, der die Authentifizierung handhabt
- Einen Python-Client, der sich beim Server authentifiziert
Erstellen des Servers
Implementieren wir unseren Flask-Server mit grundlegenden Authentifizierungsfunktionen. Öffnen Sie die Datei server.py im VSCode-Editor:
code ~/project/auth_demo/server.py
Fügen Sie nun den folgenden Code hinzu, um einen einfachen Authentifizierungsserver zu implementieren:
from flask import Flask, request, jsonify, session
import os
app = Flask(__name__)
## Generate a random secret key for session management
app.secret_key = os.urandom(24)
## Simple in-memory user database
users = {
"alice": "password123",
"bob": "qwerty456"
}
@app.route('/login', methods=['POST'])
def login():
data = request.get_json()
## Extract username and password from the request
username = data.get('username')
password = data.get('password')
## Check if the user exists and the password is correct
if username in users and users[username] == password:
session['logged_in'] = True
session['username'] = username
return jsonify({"status": "success", "message": f"Welcome {username}!"})
else:
return jsonify({"status": "error", "message": "Invalid credentials"}), 401
@app.route('/protected', methods=['GET'])
def protected():
## Check if the user is logged in
if session.get('logged_in'):
return jsonify({
"status": "success",
"message": f"You are viewing protected content, {session.get('username')}!"
})
else:
return jsonify({"status": "error", "message": "Authentication required"}), 401
@app.route('/logout', methods=['POST'])
def logout():
## Remove session data
session.pop('logged_in', None)
session.pop('username', None)
return jsonify({"status": "success", "message": "Logged out successfully"})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
Dieser Server:
- Verwendet ein einfaches In-Memory-Wörterbuch, um Benutzernamen und Passwörter zu speichern
- Stellt Endpunkte für Login, den Zugriff auf geschützte Inhalte und Logout bereit
- Verwendet Flasks Sitzungsverwaltung zur Aufrechterhaltung des Authentifizierungsstatus
Erstellen des Clients
Erstellen wir nun einen Client, der sich bei unserem Server authentifizieren kann. Öffnen Sie die Datei client.py:
code ~/project/auth_demo/client.py
Fügen Sie den folgenden Code hinzu:
import requests
import json
## Server URL
BASE_URL = "http://localhost:5000"
def login(username, password):
"""Authenticate with the server using username and password"""
response = requests.post(
f"{BASE_URL}/login",
json={"username": username, "password": password}
)
print(f"Login response: {response.status_code}")
print(response.json())
## Return the session cookies if login was successful
return response.cookies if response.status_code == 200 else None
def access_protected(cookies=None):
"""Access a protected resource"""
response = requests.get(f"{BASE_URL}/protected", cookies=cookies)
print(f"Protected resource response: {response.status_code}")
print(response.json())
return response
def logout(cookies=None):
"""Logout from the server"""
response = requests.post(f"{BASE_URL}/logout", cookies=cookies)
print(f"Logout response: {response.status_code}")
print(response.json())
return response
if __name__ == "__main__":
## Test with valid credentials
print("=== Authenticating with valid credentials ===")
cookies = login("alice", "password123")
if cookies:
print("\n=== Accessing protected resource ===")
access_protected(cookies)
print("\n=== Logging out ===")
logout(cookies)
## Test with invalid credentials
print("\n=== Authenticating with invalid credentials ===")
login("alice", "wrongpassword")
## Try to access protected resource without authentication
print("\n=== Accessing protected resource without authentication ===")
access_protected()
Dieser Client:
- Stellt Funktionen zum Anmelden, zum Zugriff auf eine geschützte Ressource und zum Abmelden bereit
- Verarbeitet Cookies, um die Sitzung zwischen Anfragen aufrechtzuerhalten
- Testet sowohl gültige als auch ungültige Anmeldeinformationen
Ausführen des Authentifizierungssystems
Um unser Authentifizierungssystem in Aktion zu sehen, müssen wir sowohl den Server als auch den Client ausführen. Starten wir zuerst den Server:
python ~/project/auth_demo/server.py
Sie sollten eine Ausgabe ähnlich dieser sehen:
* Serving Flask app 'server'
* Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
Öffnen Sie nun einen neuen Terminal-Tab, indem Sie auf die Schaltfläche "+" neben dem Terminal klicken, und führen Sie den Client aus:
cd ~/project/auth_demo
python client.py
Sie sollten eine Ausgabe sehen, die Folgendes demonstriert:
- Erfolgreiche Anmeldung mit gültigen Anmeldeinformationen
- Zugriff auf geschützte Ressourcen mit gültiger Authentifizierung
- Erfolgreiche Abmeldung
- Fehlgeschlagener Anmeldeversuch mit falschen Anmeldeinformationen
- Fehlgeschlagener Versuch, auf geschützte Ressourcen ohne Authentifizierung zuzugreifen
Diese Ausgabe bestätigt, dass unser grundlegendes Benutzername- und Passwort-Authentifizierungssystem korrekt funktioniert.
Im nächsten Schritt werden wir dieses System erweitern, indem wir eine tokenbasierte Authentifizierung implementieren, um die Sicherheit zu verbessern.
Implementierung der tokenbasierten Authentifizierung
Im vorherigen Schritt haben wir ein grundlegendes Authentifizierungssystem unter Verwendung von Sitzungen erstellt. Während dies für einfache Anwendungen funktioniert, bietet die tokenbasierte Authentifizierung mehrere Vorteile, insbesondere für APIs und verteilte Systeme.
Bei der tokenbasierten Authentifizierung:
- Der Server generiert nach erfolgreicher Authentifizierung ein Token
- Der Client speichert und sendet dieses Token mit nachfolgenden Anfragen
- Der Server validiert das Token, anstatt jedes Mal Anmeldeinformationen zu überprüfen
Lassen Sie uns unser System auf JSON Web Tokens (JWT) umstellen, einem beliebten Standard für die tokenbasierte Authentifizierung.
Installieren der erforderlichen Pakete
Zuerst müssen wir das PyJWT-Paket installieren:
pip install pyjwt
Sie sollten eine Ausgabe sehen, die die Installation bestätigt:
Collecting pyjwt
Downloading PyJWT-2.6.0-py3-none-any.whl (20 kB)
Installing collected packages: pyjwt
Successfully installed pyjwt-2.6.0
Aktualisieren des Servers für die tokenbasierte Authentifizierung
Ändern wir unseren Server so, dass er JWT-Tokens anstelle von Sitzungen verwendet. Aktualisieren Sie die Datei server.py:
code ~/project/auth_demo/server.py
Ersetzen Sie den vorhandenen Code durch:
from flask import Flask, request, jsonify
import jwt
import datetime
import os
app = Flask(__name__)
## Secret key for signing JWT tokens
SECRET_KEY = os.urandom(24)
## Simple in-memory user database
users = {
"alice": "password123",
"bob": "qwerty456"
}
def generate_token(username):
"""Generate a JWT token for the authenticated user"""
## Token expires after 30 minutes
expiration = datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
payload = {
'username': username,
'exp': expiration
}
## Create the JWT token
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
return token
def verify_token(token):
"""Verify the JWT token"""
try:
## Decode and verify the token
payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
return payload
except jwt.ExpiredSignatureError:
## Token has expired
return None
except jwt.InvalidTokenError:
## Invalid token
return None
@app.route('/login', methods=['POST'])
def login():
data = request.get_json()
## Extract username and password from the request
username = data.get('username')
password = data.get('password')
## Check if the user exists and the password is correct
if username in users and users[username] == password:
## Generate a JWT token
token = generate_token(username)
return jsonify({
"status": "success",
"message": f"Welcome {username}!",
"token": token
})
else:
return jsonify({"status": "error", "message": "Invalid credentials"}), 401
@app.route('/protected', methods=['GET'])
def protected():
## Get the token from the Authorization header
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return jsonify({"status": "error", "message": "Missing or invalid token"}), 401
## Extract the token
token = auth_header.split(' ')[1]
## Verify the token
payload = verify_token(token)
if payload:
return jsonify({
"status": "success",
"message": f"You are viewing protected content, {payload['username']}!"
})
else:
return jsonify({"status": "error", "message": "Invalid or expired token"}), 401
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
Dieser aktualisierte Server:
- Generiert JWT-Tokens nach erfolgreicher Authentifizierung
- Validiert Tokens für geschützte Ressourcen
- Verfügt über Endpunkte für Login und den Zugriff auf geschützte Inhalte
Aktualisieren des Clients für die tokenbasierte Authentifizierung
Aktualisieren wir nun unseren Client, um die JWT-Tokens zu verwenden. Aktualisieren Sie die Datei client.py:
code ~/project/auth_demo/client.py
Ersetzen Sie den vorhandenen Code durch:
import requests
import json
## Server URL
BASE_URL = "http://localhost:5000"
def login(username, password):
"""Authenticate with the server using username and password"""
response = requests.post(
f"{BASE_URL}/login",
json={"username": username, "password": password}
)
print(f"Login response: {response.status_code}")
data = response.json()
print(data)
## Return the token if login was successful
return data.get('token') if response.status_code == 200 else None
def access_protected(token=None):
"""Access a protected resource using JWT token"""
headers = {}
if token:
headers['Authorization'] = f'Bearer {token}'
response = requests.get(f"{BASE_URL}/protected", headers=headers)
print(f"Protected resource response: {response.status_code}")
print(response.json())
return response
if __name__ == "__main__":
## Test with valid credentials
print("=== Authenticating with valid credentials ===")
token = login("alice", "password123")
if token:
print("\n=== Accessing protected resource with valid token ===")
access_protected(token)
## Test with invalid credentials
print("\n=== Authenticating with invalid credentials ===")
login("alice", "wrongpassword")
## Try to access protected resource without token
print("\n=== Accessing protected resource without token ===")
access_protected()
## Try to access protected resource with invalid token
print("\n=== Accessing protected resource with invalid token ===")
access_protected("invalid.token.value")
Dieser aktualisierte Client:
- Ruft das JWT-Token nach erfolgreicher Authentifizierung ab und speichert es
- Sendet das Token im Authorization-Header für den Zugriff auf geschützte Ressourcen
- Testet verschiedene Szenarien, einschließlich gültiger und ungültiger Authentifizierungsversuche
Ausführen des tokenbasierten Authentifizierungssystems
Führen wir nun unser aktualisiertes tokenbasiertes Authentifizierungssystem aus. Beenden Sie zuerst alle laufenden Serverprozesse mit Ctrl+C und starten Sie dann den aktualisierten Server:
python ~/project/auth_demo/server.py
Öffnen Sie einen neuen Terminal-Tab oder verwenden Sie den vorhandenen zweiten Tab, um den Client auszuführen:
cd ~/project/auth_demo
python client.py
Sie sollten eine Ausgabe sehen, die Folgendes demonstriert:
- Erfolgreiche Anmeldung mit gültigen Anmeldeinformationen, Erhalt eines JWT-Tokens
- Zugriff auf geschützte Ressourcen mit einem gültigen Token
- Fehlgeschlagener Anmeldeversuch mit falschen Anmeldeinformationen
- Fehlgeschlagener Versuch, auf geschützte Ressourcen ohne Token zuzugreifen
- Fehlgeschlagener Versuch, auf geschützte Ressourcen mit einem ungültigen Token zuzugreifen
Diese Ausgabe bestätigt, dass unser tokenbasiertes Authentifizierungssystem korrekt funktioniert.
Vorteile der tokenbasierten Authentifizierung
Die tokenbasierte Authentifizierung bietet gegenüber der sitzungsbasierten Authentifizierung mehrere Vorteile:
- Zustandslos (Stateless): Der Server muss keine Sitzungsinformationen speichern.
- Skalierbarkeit: Funktioniert gut in verteilten Umgebungen mit mehreren Servern.
- Mobilfreundlich: Geeignet für mobile Anwendungen, bei denen Cookies möglicherweise nicht gut funktionieren.
- Domänenübergreifend (Cross-domain): Kann problemlos über verschiedene Domänen hinweg verwendet werden.
- Sicherheit: Tokens können so konfiguriert werden, dass sie ablaufen, wodurch das Risiko von Sitzungsübernahmen verringert wird.
In realen Anwendungen möchten Sie Ihr Authentifizierungssystem möglicherweise mit Funktionen wie Token-Aktualisierung, rollenbasierter Zugriffskontrolle und sicherer Tokenspeicherung weiter verbessern.
Erhöhung der Sicherheit mit Passwort-Hashing
In unseren vorherigen Implementierungen haben wir Passwörter im Klartext gespeichert, was ein erhebliches Sicherheitsrisiko darstellt. In diesem Schritt verbessern wir unser Authentifizierungssystem, indem wir das Passwort-Hashing mit dem bcrypt-Algorithmus implementieren.
Warum Passwörter hashen?
Das Speichern von Passwörtern im Klartext birgt mehrere Sicherheitsrisiken:
- Wenn Ihre Datenbank kompromittiert wird, können Angreifer die Passwörter sofort verwenden
- Benutzer verwenden oft Passwörter auf mehreren Websites wieder, sodass eine Verletzung andere Dienste beeinträchtigen kann
- Es verstößt gegen bewährte Sicherheitspraktiken und kann gegen Datenschutzbestimmungen verstoßen
Das Hashing von Passwörtern löst diese Probleme durch:
- Umwandlung von Passwörtern in Zeichenfolgen fester Länge, die nicht umkehrbar sind
- Hinzufügen eines "Salz" (Salt), um zu verhindern, dass Angreifer vorgefertigte Nachschlagetabellen (Rainbow Tables) verwenden
- Sicherstellen, dass selbst wenn zwei Benutzer dasselbe Passwort haben, ihre Hashes unterschiedlich sind
Installieren der erforderlichen Pakete
Zuerst müssen wir das bcrypt-Paket installieren:
pip install bcrypt
Sie sollten eine Ausgabe sehen, die die Installation bestätigt:
Collecting bcrypt
Downloading bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl (593 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 593.8/593.8 KB 10.5 MB/s eta 0:00:00
Installing collected packages: bcrypt
Successfully installed bcrypt-4.0.1
Erstellen eines Benutzerregistrierungssystems
Erweitern wir unseren Server, um die Benutzerregistrierung mit Passwort-Hashing einzubeziehen. Aktualisieren Sie die Datei server.py:
code ~/project/auth_demo/server.py
Ersetzen Sie den vorhandenen Code durch:
from flask import Flask, request, jsonify
import jwt
import datetime
import os
import bcrypt
app = Flask(__name__)
## Secret key for signing JWT tokens
SECRET_KEY = os.urandom(24)
## Store users as a dictionary with username as key and a dict of hashed password and roles as value
users = {}
def hash_password(password):
"""Hash a password using bcrypt"""
## Convert password to bytes if it's a string
if isinstance(password, str):
password = password.encode('utf-8')
## Generate a salt and hash the password
salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(password, salt)
return hashed
def check_password(password, hashed):
"""Verify a password against its hash"""
## Convert password to bytes if it's a string
if isinstance(password, str):
password = password.encode('utf-8')
## Check if the password matches the hash
return bcrypt.checkpw(password, hashed)
def generate_token(username, role):
"""Generate a JWT token for the authenticated user"""
## Token expires after 30 minutes
expiration = datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
payload = {
'username': username,
'role': role,
'exp': expiration
}
## Create the JWT token
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
return token
def verify_token(token):
"""Verify the JWT token"""
try:
## Decode and verify the token
payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
return payload
except jwt.ExpiredSignatureError:
## Token has expired
return None
except jwt.InvalidTokenError:
## Invalid token
return None
@app.route('/register', methods=['POST'])
def register():
data = request.get_json()
## Extract registration data
username = data.get('username')
password = data.get('password')
## Basic validation
if not username or not password:
return jsonify({"status": "error", "message": "Username and password are required"}), 400
## Check if the username already exists
if username in users:
return jsonify({"status": "error", "message": "Username already exists"}), 409
## Hash the password and store the user
hashed_password = hash_password(password)
users[username] = {
'password': hashed_password,
'role': 'user' ## Default role
}
return jsonify({
"status": "success",
"message": f"User {username} registered successfully"
})
@app.route('/login', methods=['POST'])
def login():
data = request.get_json()
## Extract username and password from the request
username = data.get('username')
password = data.get('password')
## Check if the user exists
if username not in users:
return jsonify({"status": "error", "message": "Invalid credentials"}), 401
## Check if the password is correct
if check_password(password, users[username]['password']):
## Generate a JWT token
token = generate_token(username, users[username]['role'])
return jsonify({
"status": "success",
"message": f"Welcome {username}!",
"token": token
})
else:
return jsonify({"status": "error", "message": "Invalid credentials"}), 401
@app.route('/protected', methods=['GET'])
def protected():
## Get the token from the Authorization header
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return jsonify({"status": "error", "message": "Missing or invalid token"}), 401
## Extract the token
token = auth_header.split(' ')[1]
## Verify the token
payload = verify_token(token)
if payload:
return jsonify({
"status": "success",
"message": f"You are viewing protected content, {payload['username']}!",
"role": payload['role']
})
else:
return jsonify({"status": "error", "message": "Invalid or expired token"}), 401
@app.route('/admin', methods=['GET'])
def admin():
## Get the token from the Authorization header
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return jsonify({"status": "error", "message": "Missing or invalid token"}), 401
## Extract the token
token = auth_header.split(' ')[1]
## Verify the token
payload = verify_token(token)
if not payload:
return jsonify({"status": "error", "message": "Invalid or expired token"}), 401
## Check if user has admin role
if payload['role'] != 'admin':
return jsonify({"status": "error", "message": "Admin access required"}), 403
return jsonify({
"status": "success",
"message": f"Welcome to the admin panel, {payload['username']}!"
})
## Add an admin user for testing
admin_password = hash_password("admin123")
users["admin"] = {
'password': admin_password,
'role': 'admin'
}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
Dieser erweiterte Server:
- Verwendet bcrypt für sicheres Passwort-Hashing
- Enthält einen Benutzerregistrierungs-Endpunkt
- Fügt rollenbasierte Zugriffskontrolle hinzu (Administrator vs. reguläre Benutzer)
- Erstellt einen Administratorbenutzer für Tests vorab
Aktualisieren des Clients
Aktualisieren wir nun unseren Client, um diese neuen Funktionen zu testen. Aktualisieren Sie die Datei client.py:
code ~/project/auth_demo/client.py
Ersetzen Sie den vorhandenen Code durch:
import requests
import json
## Server URL
BASE_URL = "http://localhost:5000"
def register(username, password):
"""Register a new user"""
response = requests.post(
f"{BASE_URL}/register",
json={"username": username, "password": password}
)
print(f"Registration response: {response.status_code}")
print(response.json())
return response.status_code == 200
def login(username, password):
"""Authenticate with the server using username and password"""
response = requests.post(
f"{BASE_URL}/login",
json={"username": username, "password": password}
)
print(f"Login response: {response.status_code}")
data = response.json()
print(data)
## Return the token if login was successful
return data.get('token') if response.status_code == 200 else None
def access_protected(token=None):
"""Access a protected resource using JWT token"""
headers = {}
if token:
headers['Authorization'] = f'Bearer {token}'
response = requests.get(f"{BASE_URL}/protected", headers=headers)
print(f"Protected resource response: {response.status_code}")
print(response.json())
return response
def access_admin(token=None):
"""Access the admin panel using JWT token"""
headers = {}
if token:
headers['Authorization'] = f'Bearer {token}'
response = requests.get(f"{BASE_URL}/admin", headers=headers)
print(f"Admin panel response: {response.status_code}")
print(response.json())
return response
if __name__ == "__main__":
## Test user registration
print("=== Registering a new user ===")
register("testuser", "testpass123")
## Try to register with the same username (should fail)
print("\n=== Registering with existing username ===")
register("testuser", "differentpass")
## Test regular user login and access
print("\n=== Regular user login ===")
user_token = login("testuser", "testpass123")
if user_token:
print("\n=== Regular user accessing protected resource ===")
access_protected(user_token)
print("\n=== Regular user trying to access admin panel ===")
access_admin(user_token)
## Test admin login and access
print("\n=== Admin login ===")
admin_token = login("admin", "admin123")
if admin_token:
print("\n=== Admin accessing protected resource ===")
access_protected(admin_token)
print("\n=== Admin accessing admin panel ===")
access_admin(admin_token)
Dieser aktualisierte Client:
- Testet die Benutzerregistrierungsfunktionalität
- Demonstriert die rollenbasierte Zugriffskontrolle
- Testet sowohl reguläre Benutzer- als auch Administratorauthentifizierung
Ausführen des erweiterten Authentifizierungssystems
Führen wir nun unser erweitertes Authentifizierungssystem aus. Beenden Sie zuerst alle laufenden Serverprozesse mit Ctrl+C und starten Sie dann den aktualisierten Server:
python ~/project/auth_demo/server.py
Öffnen Sie einen neuen Terminal-Tab oder verwenden Sie den vorhandenen zweiten Tab, um den Client auszuführen:
cd ~/project/auth_demo
python client.py
Sie sollten eine Ausgabe sehen, die Folgendes demonstriert:
- Erfolgreiche Benutzerregistrierung
- Fehlgeschlagene Registrierung mit einem vorhandenen Benutzernamen
- Reguläre Benutzeranmeldung und Zugriff auf geschützte Ressourcen
- Fehlgeschlagener Versuch eines regulären Benutzers, auf das Admin-Panel zuzugreifen
- Administratoranmeldung und Zugriff auf geschützte Ressourcen und das Admin-Panel
Diese Ausgabe bestätigt, dass unser erweitertes Authentifizierungssystem mit Passwort-Hashing und rollenbasierter Zugriffskontrolle korrekt funktioniert.
Sicherheitsvorteile
Unser erweitertes System bietet jetzt:
- Sichere Passwortspeicherung: Passwörter werden mit bcrypt gehasht, einer langsamen Hashing-Funktion, die darauf ausgelegt ist, Brute-Force-Angriffen zu widerstehen.
- Rollenbasierte Zugriffskontrolle: Verschiedene Benutzer können je nach ihren Rollen unterschiedliche Zugriffsebenen haben.
- Tokenbasierte Authentifizierung: Bietet weiterhin die Vorteile von JWT-Tokens, die wir zuvor implementiert haben.
- Benutzerregistrierung: Ermöglicht die dynamische Benutzererstellung mit sicherer Passwortspeicherung.
Diese Erweiterungen machen unser Authentifizierungssystem viel robuster und für reale Anwendungen geeignet.
Zusammenfassung
In diesem Lab haben Sie gelernt, wie Sie die Authentifizierung in einem Python-Client-Server-System implementieren, von grundlegenden Konzepten bis hin zu fortgeschrittenen Techniken. Sie haben erfolgreich:
- Die grundlegenden Konzepte der Authentifizierung in Client-Server-Systemen verstanden
- Die grundlegende Benutzername- und Passwort-Authentifizierung mithilfe von Flask-Sitzungen implementiert
- Die Sicherheit mit tokenbasierter Authentifizierung unter Verwendung von JWT verbessert
- Sicheres Passwort-Hashing mit bcrypt hinzugefügt
- Rollenbasierte Zugriffskontrolle für verschiedene Benutzertypen implementiert
Diese Fähigkeiten bieten eine solide Grundlage für die Erstellung sicherer Python-Anwendungen. Denken Sie daran, dass die Authentifizierung nur ein Aspekt der Anwendungssicherheit ist - in Produktionssystemen sollten Sie auch Folgendes berücksichtigen:
- Verwendung von HTTPS für die gesamte Kommunikation
- Implementierung der Ratenbegrenzung (Rate Limiting), um Brute-Force-Angriffe zu verhindern
- Hinzufügen von Protokollierung (Logging) und Überwachung (Monitoring) für verdächtige Aktivitäten
- Aktualisierung aller Abhängigkeiten, um Sicherheitslücken zu beheben
Durch die Anwendung dieser Prinzipien können Sie Python-Anwendungen erstellen, die Benutzerdaten effektiv schützen und einen sicheren Betrieb gewährleisten.



