Dans ce tutoriel, nous utiliserons Flask-Login pour créer un système d’authentification vers l’administration de Flask.
Préparation de l’environnement virtuel
mkdir flask-tuto-login cd flask-tuto-login virtualenv -p python3.4 virtualenv source virtualenv/bin/activate mkdir source cd source
Avant de commencer, nous devons installer quelques librairies.
Pour installer mongodb, rendez-vous sur le site officiel
Installation de Flask-Login et autres dépendances
pip install flask flask-login flask-admin flask-mongoengine mongoengine
Structure du projet
Commençons par créer la structure du projet
source - app |- mod_adm |- __init__.py |- forms.py |- models.py |- views.py |- templates |- adm |- base.html |- formhelpers.html |- index.html |- login.html |- 404.html - config.py - run.py
Afin de démarrer l’application depuis run.py, ajoutez le code suivant
# Run a test server. from app import app app.run(host='0.0.0.0')
Configuration
A présent, configurons le projet
import os # Statement for enabling the development environment DEBUG = True # Define the application directory BASE_DIR = os.path.abspath(os.path.dirname(__file__)) # Application threads. A common general assumption is # using 2 per available processor cores - to handle # incoming requests using one and performing background # operations using the other. THREADS_PER_PAGE = 2 # Enable protection agains *Cross-site Request Forgery (CSRF)* CSRF_ENABLED = True # Use a secure, unique and absolutely secret key for # signing the data. CSRF_SESSION_KEY = "secret" # Secret key for signing cookies SECRET_KEY = "secret" # Connection to the user document else test database MONGODB_SETTINGS = { 'db': 'user', 'host': '127.0.0.1', 'port': 27017, }
Modèle
Définissons, un modèle utilisateur pour notre système d’authentification.
#models.py # -*- coding:utf-8 -*- from flask_login import UserMixin from app import db from werkzeug.security import generate_password_hash, check_password_hash class User(db.Document, UserMixin): email = db.StringField() password = db.StringField() def set_password(self, password): self.password = generate_password_hash(password) def check_password(self, passwd): return check_password_hash(self.password, passwd)
Formulaire
Ainsi que le formulaire associé pour la connexion d’utilisateur.
# forms.py from flask_wtf import Form from wtforms import TextField, PasswordField from wtforms.validators import Required, Email class LoginForm(Form): email = TextField('', [Email(), Required( message='Forgot your email address?')], default="my@fra.com", ) password = PasswordField('', [Required( message='Must provide a password. ;-)')], default="fra", render_kw={"placeholder": "Password"} )
Templates
Premièrement, on crée un template de base.
Bootstrap est utilisé pour designer l’interface.
#base.html <!DOCTYPE html> <html> <head> <title>Connexion utilisateur</title> <!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}"> <script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"> </script> <!-- Latest compiled and minified JavaScript --> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"> </script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"> </script> </head> <body> <div class="container"> {% block page_cont %} {% endblock %} </div> </body> </html>
Puis, ajoutons notre vue d’authentification.
#login.html {% extends "adm/base.html" %} {% block page_cont %} {% from "adm/formhelpers.html" import render_field %} <div class="row"> <div class="col-md-push-3 col-md-6"> <form method="post" action="{{ url_for('adm.login', next=next) }}"> <dl> {{ render_field(form.email) }} {{ render_field(form.password) }} {{form.hidden_tag()}} </dl> <p><input type="submit" value="Connexion"> </form> </div> </div> {% endblock %}
avec du style
input{ height: 40px; width: 100%; font-size: 1.5em; }
Ainsi que le template permettant d’afficher les erreurs.
{% macro render_field(field) %} <dt>{{ field.label }} <dd>{{ field(**kwargs)|safe }} {% if field.errors %} {% for error in field.errors %} <div class="alert alert-danger"> <p><strong>Error!</strong> {{error}}</p> </div> {% endfor %} {% endif %} </dd> {% endmacro %}
Voici le résultat :
Vues
Tout d’abord on importe les dépendances dans le fichier views.py
# Import flask dependencies from flask import ( Blueprint, request, render_template, flash, redirect ) # Import module forms from app.mod_adm.forms import LoginForm # Import module models (i.e. User) from app.mod_adm.models import User from flask_admin.base import AdminIndexView, expose from flask_admin.contrib.mongoengine import ModelView from mongoengine.queryset import DoesNotExist from flask_login import ( current_user, login_required, login_user, logout_user ) from app import login_manager
La méthode suivante retourne l’utilisateur actuel si il est trouvé.
@login_manager.user_loader def load_user(user_id): if user_id: return User.objects.get(id=user_id)
Afin d’établir un chemin vers le module adm, nous définissons un blueprint.
mod_adm = Blueprint('adm', __name__, url_prefix='/admin')
La première vue permet de gérer l’authentification utilisateur.
@mod_adm.route('/login/', methods=['GET', 'POST']) def login(): next = "/admin" # If sign in form is submitted form = LoginForm(request.form) # Verify the sign in form if form.validate(): # Create an user if not users found if len(User.objects) == 0: user = User(email=form.email.data) user.set_password(form.password.data) user.save() else: try: user = User.objects.get( email=form.email.data, ) except DoesNotExist: user = None form['email'].errors.append('Email not found') form['password'].errors.append('Password incorrect') if user is not None: if user.check_password(form.password.data): login_user(user) return redirect(next) else: flash('Wrong email or password', 'error-message') else: next = request.args.get('next') return render_template("adm/login.html", form=form, next=next)
La seconde vue permet la déconnexion.
@mod_adm.route("/logout/", methods=["GET"]) @login_required def logout(): logout_user() flash(u'Vous êtes maintenant déconnecté', 'success') return redirect("/admin/login/")
Afin d’afficher la vue d’accueil de l’administration, nous créons une vue personnalisée.
class AdminCustomView(AdminIndexView): @expose('/') def index(self): return self.render('adm/index.html') def _handle_view(self, name, **kwargs): if not self.is_accessible(): return redirect('/admin/login/') else: print("OK") def is_accessible(self): rep = False if current_user.is_authenticated: rep = True return rep
Initialisation de l’application
Pour terminer, nous définissons le fichier app/__init__.py qui initialise la base de données, la gestion d’authentification ainsi que l’administration.
#app/__init__.py # Import flask and template operators from flask import Flask, render_template from flask_mongoengine import MongoEngine from flask_admin import Admin from flask_login import LoginManager app = Flask(__name__) # Config app.config.from_object('config') # Database init db = MongoEngine(app) # Login Management login_manager = LoginManager() login_manager.login_view = "/admin/login/" login_manager.init_app(app) @app.errorhandler(404) def not_found(error): return render_template('404.html'), 404 # Import a module / component using its blueprint handler variable (mod_auth) from app.mod_adm.views import mod_adm as adm_module from app.mod_adm.views import AdminCustomView, UserView, MealView from app.mod_adm.models import User, Meal # Register blueprint(s) app.register_blueprint(adm_module, url_prefix='/admin') # Init admin admin = Admin(name='Admin', template_mode='bootstrap3', index_view=AdminCustomView()) admin.init_app(app)
Félicitations !!
Ce tutoriel se termine, vous êtes maintenant capable de gérer l’authentification d’un utilisateur avec Flask-Login.