Python Flask: werkzeug.exceptions.BadRequestKeyError

Oct 08 2020

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 &copy; 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

2 J.G. Oct 08 2020 at 22:53

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.

1 simkusr Oct 08 2020 at 21:16

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.