I am new in Python Flask and I am trying to design my personal blog. Since it is only for private use, I would like to put the "add" page for post as protected area with a username and a password just for to add and manage my posts.
In order not to show the login credentials in the source code, I decided to store in a .yaml file and retrieve them ({"Franz":{"pw":"Biberkopf"}}
) through the function login.
But when I put "Franz" as username and "Biberkopf" as password, I get this error:
werkzeug.exceptions.BadRequestKeyError
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'pw'Traceback (most recent call last)
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\app.py", line 2464, in call
return self.wsgi_app(environ, start_response)
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask_compat.py", line 39, in reraise
raise value
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask_compat.py", line 39, in reraise
raise value
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\app.py", line 1936, in dispatch_request
return self.view_functionsrule.endpoint
File "C:\Users\franc\OneDrive\Desktop\Blog_Project\blog_prova.py", line 102, in login
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")
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'
The debugger caught an exception in your WSGI application. You can now look at the traceback which led to the error.
To switch between the interactive traceback and the plaintext one, you can click on the "Traceback" headline. From the text traceback you can also create a paste of it. For code execution mouse-over the frame you want to debug and click on the console icon on the right side.
You can execute arbitrary Python code in the stack frames and there are some extra helpers available for introspection:
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)
The idea would be that, if someone tries to log in without the right username and password, an error message would be displayed. With the right credentials you can have access to the "add" page. Here my login.html page:
<!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>
I am very new to everything and I am pretty stuck and confused at the moment. Thank you very much for every suggestion.