Python Flask: werkzeug.exceptions.BadRequestKeyError

Oct 08 2020

Python Flask'ta yeniyim ve kişisel blogumu tasarlamaya çalışıyorum. Sadece kişisel kullanım için olduğu için, gönderilerimi eklemek ve yönetmek için bir kullanıcı adı ve şifre ile korunan alan olarak gönderi için "ekle" sayfasını koymak istiyorum. Giriş kimlik bilgilerini kaynak kodda göstermemek için, bir .yaml dosyasında saklamaya ve bunları {"Franz":{"pw":"Biberkopf"}}oturum açma işlevi aracılığıyla geri almaya ( ) karar verdim .

Ancak kullanıcı adı olarak "Franz" ve şifre olarak "Biberkopf" yazdığımda şu hatayı alıyorum:

werkzeug.exceptions.BadRequestKeyError

werkzeug.exceptions.BadRequestKeyError: 400 Hatalı İstek: Tarayıcı (veya proxy) bu sunucunun anlayamadığı bir istek gönderdi.
KeyError: 'pw'

Traceback (en son çağrı son)

"C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py" dosyası, satır 2464, çağrıda

dönüş self.wsgi_app (environ, start_response)

Dosya "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", satır 2450, wsgi_app içinde

yanıt = self.handle_exception (e)

"C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py" dosyası, handle_exception satırında 1867

yeniden oluşturma (exc_type, exc_value, tb)

"C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask_compat.py" dosyası, satır 39, yeniden yayında

değeri artırmak

Dosya "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", satır 2447, wsgi_app

yanıt = self.full_dispatch_request ()

Dosya "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", satır 1952, full_dispatch_request içinde

rv = self.handle_user_exception (e)

Dosya "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", satır 1821, handle_user_exception

yeniden oluşturma (exc_type, exc_value, tb)

"C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask_compat.py" dosyası, satır 39, yeniden yayında

değeri artırmak

"C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py" dosyası, 1950 satırı, full_dispatch_request içinde

rv = self.dispatch_request ()

Dispatch_request'te "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py" dosyası, satır 1936

self.view_functionsrule.endpoint döndür

Oturum açma sırasında "C: \ Users \ franc \ OneDrive \ Desktop \ Blog_Project \ blog_prova.py" dosyası, satır 102

user.id = kullanıcı adı
flask_login.login_user (kullanıcı)
dönüş yönlendirme (url_for ("ekle"))
else:
error = "Leider haben Sie die falschen Zugangsdaten."
render_template döndür ("login.html", error = error)
return render_template ("login.html")

Kod:

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

Hata ayıklayıcı, WSGI uygulamanızda bir istisna yakaladı. Şimdi hataya neden olan traceback'e bakabilirsiniz.

Etkileşimli traceback ile düz metin arasında geçiş yapmak için, "Traceback" başlığını tıklayabilirsiniz. Geri dönüş metninden bir yapıştırma da oluşturabilirsiniz. Kod yürütme için fareyi, hata ayıklamak istediğiniz çerçevenin üzerine getirin ve sağ taraftaki konsol simgesine tıklayın.

Yığın çerçevelerinde rastgele Python kodu çalıştırabilirsiniz ve iç gözlem için bazı ekstra yardımcılar mevcuttur:

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)


Buradaki fikir, birisi doğru kullanıcı adı ve şifre olmadan giriş yapmaya çalışırsa, bir hata mesajı görüntülenmesidir. Doğru kimlik bilgileriyle "ekle" sayfasına erişebilirsiniz. İşte login.html sayfam:

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

Her şeyde çok yeniyim ve şu anda oldukça sıkışmış ve kafam karışık. Her öneri için çok teşekkür ederim.

Yanıtlar

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

Hatanın nedeni muhtemelen user.is_authenticated = request.form["pw"] == users[username]["pw"], özellikle request.form["pw"]- bu pw değişkenine erişmeye çalışır, ancak bu, form tarafından iletilmemiştir.

Belki buna eşittir işaretinden sonraki boşluk neden olur - input name= "pw

Aslında orada hiç yer kullanmadığım için% 100 emin değilim. Kodu uygun şekilde biçimlendiren bir IDE kullanmak iyi bir uygulamadır. "Temiz" kod ve daha az gürültü ile hataları tespit etmek her zaman daha kolaydır.

Güncelleme

Boşluklara izin verildiği anlaşılıyor: HTML öğesi özelliğinin "=" işaretinden önce ve sonra boşluk kullanılması

Not: Belki de hata, request_loader'ı kullanmanızla ilgilidir. Yoğun bir flask-login kullanıcısıyım ve hiç request_loader kullanmadım. Belirtildiği gibi, genellikle ihtiyacınız olmayan özel bir formdur.

Belgeleri tekrar okumanızı tavsiye ederim ( https://flask-login.readthedocs.io/en/latest/#custom-login-using-request-loader ) ve ayrıca bu harika öğreticiye bir göz atın: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world

Güncelleme 2

Cep şişesi giriş belgelerini okudum. Request_loader'ı kullandığınızda, her istekte oturum açma verilerini göndermeniz gerekir, ancak yalnızca formu doldurduğunuzda gönderirsiniz.

=> Daha önce söylendiği gibi. İstek yükleyiciyi kullanmayın. Örneğin, çerez tabanlı oturum açma kullanın. Flask Login belgesine ve mega öğreticiye bakın.

1 simkusr Oct 08 2020 at 21:16

contentBlogları depolamak için veritabanınız olmalıdır . Öyleyse neden kimlik bilgilerinizi .yaml'de ifşa etmek istiyorsunuz (geçmiş nedenlerden ötürü git deposunda bulunan dosyalardaki kimlik bilgilerini asla ifşa etmeyin)? Örn. flask_loginVeya kullanırdım flask_userve üretimde komut dosyası olan bir kullanıcı oluştururum (diğer ortamlar) örn.

python create_account.py --username=username --password=password

böylece hiç kimse hesap oluşturamazsa, kullanıcı adı / parola doğrulaması bu kitaplıklardan herhangi biri tarafından ele alınır ve siz onu ifşa etmezsiniz (birinin git deponuza erişmesi veya benzeri olması durumunda).

En azından bu yaklaşımı kullanırdım.