I am working on my login route for a small flask app and am testing the part where I try to log in a good email but bad password. I want the generic "invalid username/pw combo" message so they know they made a mistake but hackers don't know what the mistake is. I get to the part where I can't believe "even this doesn't work" because all I want to do is rerender the form. I was trying to add an error message but just want to get the page to work first now.
views.py:
@application.route('/login', methods=['GET', 'POST'])
def login(message=""):
form = LoginForm()
if request.method == 'POST' and form.validate_on_submit():
email = form.email.data
password = form.password.data
user = User.query.filter_by(email=email, password=password).first()
print(user)
try:
login_user(user)
except AttributeError:
print('in the except')
form = LoginForm()
# even this doesn't work?
return render_template('login.html', form=form)
flash('Logged in successfully.')
next_url = request.args.get('next')
return redirect(next_url or url_for('main'))
return render_template('login.html', form=form)
forms.py:
from flask.ext.wtf import Form
from wtforms import StringField, BooleanField, TextField, PasswordField, validators
from wtforms.validators import Required
class LoginForm(Form):
email = StringField('email', [Required()])
password = PasswordField('password', [Required()])
the template:
{% extends "base.html" %}
{% block title %}Login{% endblock %}
{% block content %}
<h2> Welcome to the status page</h2>
<br>
<form action="{{ url_for('login') }}" method="post" name="login_user">
{{ form.hidden_tag() }}
<p>Please log in:<br>
Email:<br>
{{ form.email }}<br>
{% for error in form.email.errors %}
<p><span style="color: red">[{{ error }}]</span></p>
{% endfor %}
Password:<br>
{{ form.password }}<br>
{% for error in form.password.errors %}
<p><span style="color: red">[{{ error }}]</span></p>
{% endfor %}
</p><br>
<p><input type="submit" value="Submit"></p>
</form>
<p><a href="{{ url_for('register') }}">I need to register</a></p>
<script type="text/javascript">
</script>
{% endblock %}
Worst part is I get this antisocial error message:
127.0.0.1 - - [02/May/2016 11:47:41] "POST /login HTTP/1.1" 400 -
My dog, with vastly differing vocal cords, communicates much better than flask does with debug=True
. I'm getting those all over anywhere I try to handle a form the way I want and it raises 400. Errors besides 400 have a handy stacktrace.
Right now, GET loads the page and shows an empty form (good). A POST with the correct email/pw works and logs the user in. The bad path is a correct email that exists, but bad pw that doesn't match that user's pw
Going into the shell works past the print('in the except')
and form = LoginForm()
but fails on returning render_template
:
BadRequestKeyError: 400: Bad Request
That's all it says
I do have a view that works by taking GET or POST and handling the error. Both render the same template, only difference is if the form has errors or not:
form:
class WebsiteCheckForm(Form):
name = StringField('name')
url = StringField('url')
view:
def handle_admin_form(form):
if form.name.data:
if validators.url(form.url.data):
Website.create(name=form.name.data, url=form.url.data)
else:
form.url.errors = ("Please enter a valid URL",)
else:
manual_url = form.url.data.replace('http://', '')
if manual_url:
form.name.errors = ("Name is required if you want to add a website",)
@application.route('/admin/', methods=['GET', 'POST'])
def admin():
if current_user.is_authenticated and not current_user.approved:
return redirect(url_for('awaiting_approval'))
form = WebsiteCheckForm()
if request.method == 'GET':
form.url.data = 'http://'
db = get_db()
if request.method == 'POST':
handle_admin_form(form)
try:
delete_websites(request)
approve_users(request)
except:
redirect(url_for('admin'))
form.url.data = 'http://'
form.name.data = ''
websites = Website.query.all()
users = User.query.all()
users_needing_approval = [user for user in users if not user.approved]
return render_template('admin.html', form=form, websites=websites, users_needing_approval=users_needing_approval)
How can I make flask render template pages when I handle a form, and have it say what the error is? Thank you
ANSWER:
This poor behavior can be fixed by this answer exception for non existing parameter in FLASK
#!/usr/bin/env python
from app import application
application.config['TRAP_BAD_REQUEST_ERRORS'] = True
if __name__ == '__main__':
application.run(debug=True)
which took me to bad logic in the
@login_manager.request_loader
def request_loader(request):
portion of my flask-login
setup. A ticket is already open to fix this (the laconic 400 error)
/login
work correctly? – John Gordon/login
.) See en.wikipedia.org/wiki/Post/Redirect/Get for more details. – John Gordon