Python Flask: werkzeug.exceptions.BadRequestKeyError
Ich bin neu in Python Flask und versuche mein persönliches Blog zu gestalten. Da es nur für den privaten Gebrauch ist, möchte ich die Seite "Hinzufügen" für Posts als geschützten Bereich mit einem Benutzernamen und einem Passwort nur zum Hinzufügen und Verwalten meiner Posts einrichten. Um die Anmeldeinformationen im Quellcode nicht anzuzeigen, habe ich beschlossen, sie in einer .yaml-Datei zu speichern und sie ( {"Franz":{"pw":"Biberkopf"}}) über die Funktionsanmeldung abzurufen .
Aber wenn ich "Franz" als Benutzernamen und "Biberkopf" als Passwort eingebe, erhalte ich folgende Fehlermeldung:
werkzeug.exceptions.BadRequestKeyError
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: Der Browser (oder Proxy) hat eine Anfrage gesendet, die dieser Server nicht verstehen konnte.
KeyError: 'pw'Traceback (letzter Anruf zuletzt)
Datei "C: \ Benutzer \ Franc \ AppData \ Local \ Programme \ Python \ Python38-32 \ Lib \ Site-Pakete \ Flask \ App.py", Zeile 2464, im Aufruf
return self.wsgi_app (environ, start_response)
Datei "C: \ Benutzer \ Franc \ AppData \ Local \ Programme \ Python \ Python38-32 \ Lib \ Site-Pakete \ Flask \ App.py", Zeile 2450, in wsgi_app
response = self.handle_exception (e)
Datei "C: \ Benutzer \ Franc \ AppData \ Local \ Programme \ Python \ Python38-32 \ Lib \ Site-Pakete \ Flask \ App.py", Zeile 1867, in handle_exception
reraise (exc_type, exc_value, tb)
Datei "C: \ Benutzer \ Franc \ AppData \ Local \ Programme \ Python \ Python38-32 \ Lib \ site-packages \ flask_compat.py", Zeile 39, in reraise
Wert steigern
Datei "C: \ Benutzer \ Franc \ AppData \ Local \ Programme \ Python \ Python38-32 \ Lib \ Site-Pakete \ Flask \ App.py", Zeile 2447, in wsgi_app
response = self.full_dispatch_request ()
Datei "C: \ Benutzer \ Franc \ AppData \ Local \ Programme \ Python \ Python38-32 \ Lib \ Site-Pakete \ Flask \ App.py", Zeile 1952, in full_dispatch_request
rv = self.handle_user_exception (e)
Datei "C: \ Benutzer \ Franc \ AppData \ Local \ Programme \ Python \ Python38-32 \ Lib \ Site-Pakete \ Flask \ App.py", Zeile 1821, in handle_user_exception
reraise (exc_type, exc_value, tb)
Datei "C: \ Benutzer \ Franc \ AppData \ Local \ Programme \ Python \ Python38-32 \ Lib \ site-packages \ flask_compat.py", Zeile 39, in reraise
Wert steigern
Datei "C: \ Benutzer \ Franc \ AppData \ Local \ Programme \ Python \ Python38-32 \ Lib \ Site-Pakete \ Flask \ App.py", Zeile 1950, in full_dispatch_request
rv = self.dispatch_request ()
Datei "C: \ Benutzer \ Franc \ AppData \ Local \ Programme \ Python \ Python38-32 \ Lib \ Site-Pakete \ Flask \ App.py", Zeile 1936, in dispatch_request
return self.view_functionsrule.endpoint
Datei "C: \ Benutzer \ Franc \ OneDrive \ Desktop \ Blog_Project \ blog_prova.py", Zeile 102, im Login
user.id = Benutzername
flask_login.login_user (Benutzer)
return redirect (url_for ("add"))
else:
error = "Leider haben Sie die verschiedenen Zugangsdaten."
return render_template ("login.html", error = error)
return render_template ("login.html")
Code:
@app.route('/add')
@login_required
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\templating.py", line 136, in render_template
ctx.app.update_template_context(context)
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\app.py", line 838, in update_template_context
context.update(func())
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask_login\utils.py", line 379, in _user_context_processor
return dict(current_user=_get_user())
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask_login\utils.py", line 346, in _get_user
current_app.login_manager._load_user()
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask_login\login_manager.py", line 331, in _load_user
user = self._load_user_from_request(request)
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask_login\login_manager.py", line 390, in _load_user_from_request
user = self._request_callback(request)
File "C:\Users\franc\OneDrive\Desktop\Blog_Project\blog_prova.py", line 85, in request_loader
username = request.form.get("username") # comunica col template <input ...name = "username"> Username </input>
if username not in users:
return
user = User()
user.id = username
user.is_authenticated = request.form["pw"] == users[username]["pw"]
return user
@app.route('/login', methods=["POST", "GET"])
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\werkzeug\datastructures.py", line 442, in __getitem__
raise exceptions.BadRequestKeyError(key)
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'pw'
Der Debugger hat eine Ausnahme in Ihrer WSGI-Anwendung festgestellt. Sie können sich jetzt den Traceback ansehen, der zu dem Fehler geführt hat.
Um zwischen dem interaktiven und dem Klartext-Traceback zu wechseln, klicken Sie auf die Überschrift "Traceback". Aus dem Text-Traceback können Sie auch eine Einfügung erstellen. Für die Codeausführung fahren Sie mit der Maus über den Frame, den Sie debuggen möchten, und klicken Sie auf das Konsolensymbol auf der rechten Seite.
Sie können beliebigen Python-Code in den Stapelrahmen ausführen, und es stehen einige zusätzliche Hilfsprogramme zur Selbstbeobachtung zur Verfügung:
dump() shows all variables in the frame
dump(obj) dumps all that's known about the object
Edit: If I run the Pycharm debugger, it seems that there are some problems with the method is_authenticated (Property 'is_authenticated' cannot be set). I don´t know if it is somehow inherent.
This is my sample code:
```
from datetime import datetime
import flask_login
import yaml
from flask import Flask, render_template, request, redirect, url_for
from flask_login import LoginManager, UserMixin, login_required, logout_user
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['TESTING'] = False
app.config['SECRET_KEY'] = 'chiavesegreta'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////Users/Desktop/Blog_Project/blog2.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
# {"Franz":{"pw":"Biberkopf"}}
with open(r'C://Users//Desktop//application.yaml') as file:
users = yaml.full_load(file)
class User(UserMixin):
pass
class Blogpost2(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(50))
subtitle = db.Column(db.String(50))
author = db.Column(db.String(20))
date_posted = db.Column(db.DateTime)
content = db.Column(db.Text)
db.create_all()
@app.route('/')
def index():
posts = Blogpost2.query.order_by(Blogpost2.date_posted.desc()).all()
return render_template('index.html', posts=posts)
@app.route('/about')
def about():
return render_template('about.html')
@app.route('/post/<int:post_id>')
def post(post_id):
post = Blogpost2.query.filter_by(id=post_id).one()
date_posted = post.date_posted.strftime('%d %B, %Y')
return render_template('post.html', post=post, date_posted=date_posted)
@login_manager.user_loader
def user_loader(username):
if username not in users:
return
user = User()
user.id = username
return user
@login_manager.request_loader
def request_loader(request):
username = request.form.get("username")
if username not in users:
return
user = User()
user.id = username
user.is_authenticated = request.form["pw"] == users[username]["pw"]
return user
@app.route('/login', methods=["POST", "GET"])
def login():
error = None
if request.method == 'POST':
username = request.form.get('username')
if request.form.get('pw') == users[username]["pw"]:
user = User()
user.id = username
flask_login.login_user(user)
return redirect(url_for("add"))
else:
error = "Leider haben Sie die falschen Zugangsdaten."
return render_template("login.html", error=error)
return render_template("login.html")
@app.route('/add')
@login_required
def add():
return render_template('add.html')
@app.route('/logout')
def logout():
logout_user()
return "Logged out !"
@app.route('/contact')
def contact():
return render_template('contact.html')
@app.route('/prova')
def prova():
return render_template('prova.html')
@app.route('/addpost', methods=['POST'])
def addpost():
title = request.form['title']
subtitle = request.form['subtitle']
author = request.form["author"]
content = request.form['content']
post = Blogpost2(title=title, subtitle=subtitle, author=author, content=content, date_posted=datetime.now())
db.session.add(post)
db.session.commit()
return redirect(url_for('index'))
if __name__ == "__main__":
app.run(debug=True)
Die Idee wäre, dass eine Fehlermeldung angezeigt wird, wenn jemand versucht, sich ohne den richtigen Benutzernamen und das richtige Passwort anzumelden. Mit den richtigen Anmeldeinformationen können Sie auf die Seite "Hinzufügen" zugreifen. Hier meine login.html Seite:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Clean Blog - Start Bootstrap Theme</title>
<!-- Bootstrap core CSS -->
<!-- <link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"> -->
<link href= "{{ url_for('static', filename='bootstrap.min.css')}}" rel="stylesheet">
<!-- Custom fonts for this template -->
<!-- <link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css"> -->
<link href="{{url_for('static', filename = 'fontawesome.min.css')}}" rel="stylesheet" type="text/css">
<link href='https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<!-- Custom styles for this template -->
<link href="{{url_for('static', filename = 'clean-blog.min.css')}}" rel="stylesheet">
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
<div class="container">
<a class="navbar-brand" href= "{{ url_for('index') }}">Start Bootstrap</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('index')}}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('about')}}">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('contact')}}">Contact</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('prova')}}">Prova</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Page Header -->
<header class="masthead" style="background-image: url('img/contact-bg.jpg')">
<div class="overlay"></div>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<div class="page-heading">
<h1>Login</h1>
</div>
</div>
</div>
</div>
</header>
<hr>
<!-- Footer -->
<footer><!-- Main Content -->
<div class="container"> <!-- crea contenitore x la larghezza del layout -->
<div class="row"> <!-- crea riga -->
<div class="col-lg-8 col-md-10 mx-auto"> <!-- crea colonna -->
<p>Login zu dem privaten Area dieses Blogs</p>
<form action = "" method = "POST" name="sentMessage" id="contactForm" novalidate>
<div class="control-group">
<div class="form-group floating-label-form-group controls">
<label>Username</label>
<input name = "username" type="text" class="form-control" placeholder="Username" id="Username" required data-validation-required-message="Please enter your username." value ="{{ request.form.username }}">
<p class="help-block text-danger"></p>
</div>
</div>
<div class="control-group">
<div class="form-group floating-label-form-group controls">
<label>Password</label>
<input name= "pw" class="input" placeholder="pw" id="pw" required data-validation-required-message="Please enter your password." value = "{{ request.form.pw }}">
<p class="help-block text-danger"></p>
</div>
</div>
<div class = "container">
<div class = "row" >
<input type = "checkbox" onclick = "Toggle()">
<label> Show Password </label>
<script>
function Toggle() {
var temp = document.getElementById("typepass");
if (temp.type === "password") {
temp.type = "text";
}
else {
temp.type = "password";
}
}
</script>
</div>
</div>
<br>
<div id="success"></div>
<button type="submit" class="btn btn-primary" id="sendMessageButton">Login!</button>
</form>
{% if error %}
<p class = "error"> <strong> Error: </strong> {{ error }}
{% endif %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<!-- Qua inizia la parte inferiore-->
<p class="copyright text-muted">Copyright © Your Website 2020</p>
</div>
</div>
</div>
</footer>
<!-- Bootstrap core JavaScript -->
<script src= "{{ url_for('static', filename = 'jquery.min.js')}}"> </script>
<script src= "{{ url_for('static', filename = 'bootstrap.min.js')}}"></script>
<!-- Custom scripts for this template -->
<script src="{{ url_for('static', filename = 'clean-blog.min.js')}}"> </script>>
</body>
</html>
Ich bin in allem sehr neu und im Moment ziemlich festgefahren und verwirrt. Vielen Dank für jeden Vorschlag.
Antworten
Der Fehler wird wahrscheinlich verursacht durch user.is_authenticated = request.form["pw"] == users[username]["pw"], insbesondere durch request.form["pw"]- dies versucht, auf die pw-Variable zuzugreifen, dies wurde jedoch nicht vom Formular übertragen.
Vielleicht liegt das am Leerzeichen nach dem Gleichheitszeichen - input name= "pw
Eigentlich bin ich mir nicht 100% sicher, da ich dort nie einen Platz genutzt habe. Es wird empfohlen, eine IDE zu verwenden, die den Code ordnungsgemäß formatiert. Mit "sauberem" Code und weniger Rauschen ist es immer einfacher, Fehler zu erkennen.
Aktualisieren
Es sieht so aus, als wären Leerzeichen zulässig: Verwenden von Leerzeichen vor und nach dem Zeichen = = des HTML-Elementattributs
PS: Möglicherweise hängt der Fehler mit Ihrer Verwendung des request_loader zusammen. Ich bin ein starker Benutzer von flask-login und habe request_loader nie verwendet. Wie bereits erwähnt, handelt es sich um ein spezielles Formular, das Sie normalerweise nicht benötigen.
Ich würde empfehlen, dass Sie die Dokumentation erneut lesen ( https://flask-login.readthedocs.io/en/latest/#custom-login-using-request-loader ) und schauen Sie sich auch dieses fantastische Tutorial an: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
Update 2
Ich habe die Kolben-Login-Dokumentation gelesen. Wenn Sie den request_loader verwenden, müssen Sie die Anmeldedaten bei jeder Anfrage senden, aber Sie senden sie nur, wenn Sie das Formular ausfüllen.
=> Wie schon gesagt. Verwenden Sie nicht den Anforderungslader. Verwenden Sie zB Cookie-basiertes Login. Siehe Flask Login-Dokument und das Mega-Tutorial.
Sie sollten eine Datenbank zum Speichern der contentBlogs haben. Warum möchten Sie dann Ihre Anmeldeinformationen in .yaml verfügbar machen (machen Sie niemals Anmeldeinformationen in Dateien verfügbar, die aus historischen Gründen im Git-Repository enthalten sind)? Ich würde zB flask_loginoder verwenden flask_userund einen Benutzer mit einem Skript in der Produktion erstellen (andere Umgebungen), z
python create_account.py --username=username --password=password
Wenn also niemand ein Konto erstellen kann, wird die Überprüfung des Benutzernamens / Kennworts von einer dieser Bibliotheken durchgeführt und Sie würden es nicht verfügbar machen (falls jemand auf Ihr Git-Repository zugreift oder so).
Zumindest würde ich diesen Ansatz verwenden.