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)
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
# 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" def load_user(userid): return User.query.filter(User.id==userid).first()
Here we created an instance of the
LoginManager, initialized it with
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() 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
# ourapp/views.py from flask import redirect, url_for from flask.ext.login import logout_user from . import app def signout(): logout_user() return redirect(url_for('index'))