Python Flask : werkzeug.exceptions.BadRequestKeyError

Oct 08 2020

저는 Python Flask를 처음 사용하며 개인 블로그를 디자인하려고합니다. 사적인 용도로만 사용하기 때문에 게시물을 추가하고 관리하기 위해 사용자 이름과 비밀번호가있는 보호 영역으로 게시물의 "추가"페이지를 추가하고 싶습니다. 소스 코드에 로그인 자격 증명을 표시하지 않기 위해 .yaml 파일에 저장하고 {"Franz":{"pw":"Biberkopf"}}로그인 함수를 통해 검색 ( ) 하기로 결정했습니다 .

그러나 "Franz"를 사용자 이름으로, "Biberkopf"를 암호로 입력하면이 오류가 발생합니다.

werkzeug.exceptions.BadRequestKeyError

werkzeug.exceptions.BadRequestKeyError : 400 잘못된 요청 : 브라우저 (또는 프록시)가이 서버가 이해할 수없는 요청을 보냈습니다.
KeyError : 'pw'

역 추적 (가장 최근 호출 마지막)

파일 "C : \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", 2464 행, 통화 중

return self.wsgi_app (environ, start_response)

wsgi_app에있는 "C : \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", 2450 행 파일

응답 = self.handle_exception (e)

파일 "C : \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", 줄 1867, handle_exception

reraise (exc_type, exc_value, tb)

파일 "C : \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask_compat.py", 39 행, reraise

가치를 높이다

wsgi_app에있는 "C : \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", 2447 행 파일

응답 = self.full_dispatch_request ()

full_dispatch_request의 파일 "C : \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", 1952 행

rv = self.handle_user_exception (e)

handle_user_exception의 파일 "C : \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", 1821 행

reraise (exc_type, exc_value, tb)

파일 "C : \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask_compat.py", 39 행, reraise

가치를 높이다

full_dispatch_request의 파일 "C : \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", 1950 행

rv = self.dispatch_request ()

dispatch_request의 파일 "C : \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-packages \ flask \ app.py", 줄 1936

self.view_functionsrule.endpoint 반환

파일 "C : \ Users \ franc \ OneDrive \ Desktop \ Blog_Project \ blog_prova.py", 라인 102, 로그인

user.id = 사용자 이름
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

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'

디버거가 WSGI 애플리케이션에서 예외를 포착했습니다. 이제 오류를 일으킨 역 추적을 볼 수 있습니다.

대화 형 트레이스 백과 일반 텍스트 사이를 전환하려면 "Traceback"헤드 라인을 클릭하십시오. 텍스트 트레이스 백에서 붙여 넣기를 만들 수도 있습니다. 코드 실행을 위해 디버그하려는 프레임 위에 마우스를 놓고 오른쪽에있는 콘솔 아이콘을 클릭합니다.

스택 프레임에서 임의의 Python 코드를 실행할 수 있으며 내부 검사에 사용할 수있는 몇 가지 추가 도우미가 있습니다.

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)


누군가가 올바른 사용자 이름과 암호없이 로그인을 시도하면 오류 메시지가 표시된다는 아이디어가 있습니다. 올바른 자격 증명이 있으면 "추가"페이지에 액세스 할 수 있습니다. 여기 내 login.html 페이지 :

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

나는 모든 것에 매우 익숙하며 현재 꽤 갇혀 있고 혼란 스럽습니다. 모든 제안에 감사드립니다.

답변

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

이 오류는 아마도 user.is_authenticated = request.form["pw"] == users[username]["pw"], 특히 request.form["pw"]pw 변수에 액세스하려고 시도하기 때문에 발생 하지만 이는 양식에서 전송되지 않았습니다.

등호 뒤의 공백 때문일 수 있습니다. input name= "pw

사실 저는 그곳에서 공간을 사용하지 않았기 때문에 100 % 확신하지 못합니다. 코드를 적절하게 형식화하는 IDE를 사용하는 것이 좋습니다. "깨끗한"코드와 적은 노이즈로 오류를 발견하기가 더 쉽습니다.

최신 정보

공백이 허용 된 것 같습니다. HTML 요소 속성의 '='기호 앞뒤에 공백 사용

추신 : 아마도 오류는 request_loader 사용과 관련이 있습니다. 나는 flask-login을 많이 사용하고 request_loader를 사용한 적이 없습니다. 언급했듯이 일반적으로 필요하지 않은 특수한 양식입니다.

문서를 다시 읽어 보시기 바랍니다 ( https://flask-login.readthedocs.io/en/latest/#custom-login-using-request-loader ) 그리고이 환상적인 튜토리얼을 살펴보십시오. https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world

업데이트 2

플라스크 로그인 문서를 읽었습니다. request_loader를 사용할 때 모든 요청과 함께 로그인 데이터를 보내야하지만 양식을 채울 때만 보냅니다.

=> 앞서 말했듯이. 요청 로더를 사용하지 마십시오. 예를 들어 쿠키 기반 로그인을 사용하십시오. Flask 로그인 문서 및 메가 자습서를 참조하세요.

1 simkusr Oct 08 2020 at 21:16

content블로그 를 저장할 데이터베이스가 있어야합니다 . 그렇다면 .yaml에서 자격 증명을 노출하려는 이유는 무엇입니까 (기록적인 이유로 git 저장소에 포함 된 파일에 자격 증명을 노출하지 마십시오)? 나는 예를 사용 flask_login하거나 flask_user프로덕션 (다른 환경)에서 스크립트로 사용자를 만듭니다.

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

아무도 계정을 만들 수 없으므로 해당 라이브러리 중 하나에서 사용자 이름 / 암호 유효성 검사를 처리하고 노출하지 않습니다 (어떤 사람이 git 저장소에 액세스하는 경우 등).

적어도 나는이 접근법을 사용할 것입니다.