Now that we've got a user in the database, we can implement authentication. We'll want to let a user submit a form with their username and password (though this might be email and password for some apps), then make sure that they gave us the correct password. If it all checks out, we'll mark them as authenticated by setting a cookie in their browser. The next time they make a request we'll know that they have already logged in by looking for that cookie.
Let's start by defining a UsernamePassword
form with WTForms.
# ourapp/forms.py
from flask_wtf import Form
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired
class UsernamePasswordForm(Form):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
Next we'll add a method to our user model that compares a string with the hashed password stored for that user.
# ourapp/models.py
from . import db
class User(db.Model):
# [...] columns and properties
def is_correct_password(self, plaintext)
return bcrypt.check_password_hash(self._password, plaintext)
12.3.1. Flask-Login
Our next goal is to define a sign-in view that serves and accepts our form. If the user enters the correct credentials, we will authenticate them using the Flask-Login extension. This extension simplifies the process of handling user sessions and authentication.
We need to do a little bit of configuration to get Flask-Login ready to roll.
In init.py we'll define the Flask-Login login_manager
.
# ourapp/__init__.py
from flask.ext.login import LoginManager
# Create and configure app
# [...]
from .models import User
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "signin"
@login_manager.user_loader
def load_user(userid):
return User.query.filter(User.id==userid).first()
Here we created an instance of the LoginManager
, initialized it with
our app
object, defined the login view and told it how to get a user
object with a user's id
. This is the baseline configuration we should
have for Flask-Login.
Note See more ways to customize Flask-Login.
Now we can define the signin
view that will handle authentication.
# ourapp/views.py
from flask import redirect, url_for
from flask.ext.login import login_user
from . import app
from .forms import UsernamePasswordForm()
@app.route('signin', methods=["GET", "POST"])
def signin():
form = UsernamePasswordForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first_or_404()
if user.is_correct_password(form.password.data):
login_user(user)
return redirect(url_for('index'))
else:
return redirect(url_for('signin'))
return render_template('signin.html', form=form)
We simply import the login_user
function from Flask-Login, check a
user's login credentials and call login_user(user)
. You can log the
current user out with logout_user()
.
# ourapp/views.py
from flask import redirect, url_for
from flask.ext.login import logout_user
from . import app
@app.route('/signout')
def signout():
logout_user()
return redirect(url_for('index'))