Dans la partie précédente de cette série, nous avons vu comment démarrer avec Python Flask et MySQL et implémenté la partie d'enregistrement des utilisateurs de notre application. Dans ce didacticiel, nous allons passer au niveau supérieur en implémentant la fonctionnalité de connexion et de déconnexion pour notre application.
Mise en route
Clonez d'abord le code source du tutoriel précédent depuis GitHub.
git clone https://github.com/tutsplus/create-a-web-app-from-scratch-using-python-flask-and-mysql/.git
Une fois le code source cloné, accédez à la part-1 répertoire et démarrez le serveur.
python app.py
Pointez votre navigateur sur https://localhost:5000 et vous devriez avoir l'application en cours d'exécution.
Création de l'interface de connexion
Accédez à FlaskApp/templates et créez un nouveau fichier appelé signin.html . Ouvrez signin.html et ajoutez le code HTML suivant :
<!DOCTYPE html> <html lang="en"> <head> <title>Python Flask Bucket List App - Sign In</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" /> <link href="../static/signup.css" rel="stylesheet" /> </head> <body> <div class="container"> <div class="header"> <nav class="border-bottom flex-wrap mb-4 py-3 d-flex justify-content-center" > <a href="/" class="text-dark text-decoration-none mb-3 mb-md-0 d-flex align-items-center me-md-auto" > <span class="fs-4">Python Flask App</span> </a> <ul class="nav nav-pills"> <li class="nav-item"> <a href="/" class="nav-link">Home</a> </li> <li class="nav-item"> <a href="/signup" class="nav-link">Signup</a> </li> <li class="nav-item"> <a href="/signin" class="nav-link active" aria-current="page" >Sign In</a > </li> </ul> </nav> </div> <div class="bg-light rounded-3 mb-4 p-5"> <div class="container-fluid py-5"> <h1 class="text-center fw-bold display-5">Bucket List App</h1> <form class="form-signin" action="/api/validateLogin" method="post"> <label for="inputEmail" class="sr-only">Email address</label> <input type="email" name="inputEmail" id="inputEmail" class="form-control" placeholder="Email address" required autofocus> <label for="inputPassword" class="sr-only">Password</label> <input type="password" name="inputPassword" id="inputPassword" class="form-control" placeholder="Password" required> <button id="btnSignIn" class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button> </form> </div> <footer class="footer"> <p>© Company 2022</p> </footer> </div> </body> </html>
Ouvrez app.py et ajoutez une nouvelle route pour l'interface de connexion.
@app.route('/signin') def showSignin(): return render_template('signin.html')
Ensuite, ouvrez index.html et signup.html , et ajoutez le href
lien pour la connexion sur les deux pages en tant que /signin
. Enregistrez toutes les modifications et redémarrez le serveur.
python app.py
Pointez votre navigateur sur http://localhost:5000 et cliquez sur Connexion lien, et vous devriez pouvoir voir la page de connexion.
Mise en œuvre de la connexion
Maintenant, nous devons créer une fonction pour valider la connexion de l'utilisateur. En cliquant sur Connexion , nous publierons l'adresse e-mail et le mot de passe saisis dans la fonction de validation de l'utilisateur.
Création d'une procédure stockée
Pour valider un utilisateur, nous aurons besoin d'une procédure stockée MySQL. Créez donc une procédure stockée MySQL comme indiqué :
DELIMITER $$ CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_validateLogin`( IN p_username VARCHAR(20) ) BEGIN select * from tbl_user where user_username = p_username; END$$ DELIMITER ;
Nous obtiendrons les détails de l'utilisateur en fonction du username
depuis la base de données MySQL en utilisant sp_validateLogin
. Une fois que nous aurons le mot de passe haché, nous le validerons par rapport au mot de passe saisi par l'utilisateur.
Valider la méthode utilisateur
Créez une méthode pour valider l'utilisateur que nous appellerons lorsque l'utilisateur soumettra le formulaire :
@app.route('/api/validateLogin',methods=['POST']) def validateLogin(): try: _username = request.form['inputEmail'] _password = request.form['inputPassword'] except Exception as e: return render_template('error.html',error = str(e))
Comme on le voit dans le code ci-dessus, nous avons lu l'adresse e-mail et le mot de passe affichés dans _username
et _password
. Nous allons maintenant appeler le sp_validateLogin
procédure avec le paramètre _username
. Créez donc une connexion MySQL dans le validatelogin
méthode :
con = mysql.connect()
Une fois la connexion créée, créez un cursor
en utilisant le con
connexion.
cursor = con.cursor()
À l'aide du curseur, appelez la procédure stockée MySQL comme indiqué :
cursor.callproc('sp_validateLogin',(_username,))
Obtenez les enregistrements récupérés à partir du curseur comme indiqué :
data = cursor.fetchall()
Si les données contiennent des enregistrements, nous associerons le mot de passe récupéré au mot de passe saisi par l'utilisateur.
if len(data) > 0: if check_password_hash(str(data[0][3]),_password): return redirect('/userhome') else: return render_template('error.html',error = 'Wrong Email address or Password.') else: return render_template('error.html',error = 'Wrong Email address or Password.')
Comme on le voit dans le code ci-dessus, nous avons utilisé une méthode appelée check_password_hash
pour vérifier si le mot de passe de hachage renvoyé correspond au mot de passe saisi par l'utilisateur. Si tout va bien, nous redirigerons l'utilisateur vers userHome.html . Et s'il y a une erreur, nous afficherons error.html avec le message d'erreur.
Voici le validateLogin
complet code :
@app.route('/api/validateLogin',methods=['POST']) def validateLogin(): try: _username = request.form['inputEmail'] _password = request.form['inputPassword'] # connect to mysql con = mysql.connect() cursor = con.cursor() cursor.callproc('sp_validateLogin',(_username,)) data = cursor.fetchall() if len(data) > 0: if check_password_hash(str(data[0][3]),_password): session['user'] = data[0][0] return redirect('/userHome') else: return render_template('error.html',error = 'Wrong Email address or Password') else: return render_template('error.html',error = 'Wrong Email address or Password') except Exception as e: return render_template('error.html',error = str(e)) finally: cursor.close() con.close()
Créez une page appelée userhome.html dans le dossier des modèles et ajoutez le code HTML suivant :
<!DOCTYPE html> <html lang="en"> <head> <title>Python Flask Bucket List App - Home</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" /> </head> <body> <div class="container"> <div class="header"> <nav class="border-bottom flex-wrap mb-4 py-3 d-flex justify-content-center" > <a href="/" class="text-dark text-decoration-none mb-3 mb-md-0 d-flex align-items-center me-md-auto" > <span class="fs-4">Python Flask App</span> </a> <ul class="nav nav-pills"> <li class="nav-item"> <a href="/userhome" class="nav-link">Home</a> </li> <li class="nav-item"> <a href="/logout" class="nav-link active">Logout</a> </li> </ul> </nav> </div> <div class="bg-light rounded-3 mb-4 p-5"> <div class="container-fluid py-5"> <h1 class="text-center fw-bold display-5">Welcome Home!</h1> </div> </div> <footer class="footer"> <p>© Company 2022</p> </footer> </div> </body> </html>
Créez également une page d'erreur appelée error.html dans les templates
dossier et ajoutez le code HTML suivant :
<!DOCTYPE html> <html lang="en"> <head> <title>Error - Python Flask App</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" /> </head> <body> <div class="container"> <div class="header"> <nav class="border-bottom flex-wrap mb-4 py-3 d-flex justify-content-center" > <a href="/" class="text-dark text-decoration-none mb-3 mb-md-0 d-flex align-items-center me-md-auto" > <span class="fs-4">Python Flask App</span> </a> <ul class="nav nav-pills"> <li class="nav-item"> <a href="/" class="nav-link">Home</a> </li> <li class="nav-item"> <a href="/signup" class="nav-link">Signup</a> </li> <li class="nav-item"> <a href="/signin" class="nav-link">Sign In</a> </li> </ul> </nav> </div> <div class="bg-light rounded-3 mb-4 p-5"> <div class="container-fluid py-5"> <h1 class="text-center fw-bold display-5">{{error}}</h1> </div> </div> <footer class="footer"> <p>© Company 2022</p> </footer> </div> </body> </html>
Dans error.html , nous avons un élément comme indiqué :
<h1 class="text-center fw-bold display-5">{{error}}</h1>
La valeur de la variable peut être transmise depuis le render_template
fonction et peut être défini dynamiquement.
Une fois la connexion réussie, nous redirigeons l'utilisateur vers la page d'accueil de l'utilisateur, nous devons donc créer une route appelée /userHome
comme indiqué :
@app.route('/userHome') def userHome(): return render_template('userHome.html')
Enregistrez toutes les modifications et redémarrez le serveur. Cliquez sur Connexion sur la page d'accueil et essayez de vous connecter à l'aide d'une adresse e-mail et d'un mot de passe valides. Une fois la validation de l'utilisateur réussie, vous devriez avoir une page comme illustré ci-dessous :
En cas d'échec de la validation de l'utilisateur, l'utilisateur sera redirigé vers une page d'erreur comme indiqué ci-dessous :
Ici, nous avons utilisé une page d'erreur distincte pour afficher l'erreur. C'est également très bien si vous souhaitez utiliser la même page pour afficher le message d'erreur.
Restreindre l'accès non autorisé à la page d'accueil de l'utilisateur
En cas de validation réussie de l'utilisateur, un utilisateur est redirigé vers la page d'accueil de l'utilisateur. Mais à l'heure actuelle, même un utilisateur non autorisé peut afficher la page d'accueil en parcourant simplement l'URL http://localhost:5000/userhome.
Pour restreindre l'accès des utilisateurs non autorisés, nous vérifierons une variable de session que nous définirons lors de la connexion réussie de l'utilisateur. Alors importez session
du flacon :
from flask import session
Nous devons également définir une clé secrète pour la session. Donc dans app.py
, une fois l'application initialisée, définissez la clé secrète comme indiqué :
app.secret_key = 'why would I tell you my secret key?'
Maintenant, à l'intérieur du validateLogin
méthode, avant de rediriger l'utilisateur vers /userhome
une fois la connexion réussie, définissez la session
variable comme indiqué :
session['user'] = data[0][0]
Ensuite, dans le userhome
méthode, vérifiez la variable de session avant de rendre userhome.html
. Si la variable de session est introuvable, redirigez vers la page d'erreur.
@app.route('/userhome') def userHome(): if session.get('user'): return render_template('userhome.html') else: return render_template('error.html',error = 'Unauthorized Access')
Enregistrez toutes les modifications et redémarrez le serveur. Sans vous connecter, essayez d'accéder à http://localhost:5000/userhome et puisque vous n'êtes pas encore connecté, vous devriez être redirigé vers la page d'erreur.
Mise en œuvre de la déconnexion
La mise en œuvre de la fonctionnalité de déconnexion est la plus simple. Tout ce que nous avons à faire est de rendre la variable de session user
null et rediriger l'utilisateur vers la page principale.
Dans app.py , créez une nouvelle route et une nouvelle méthode pour logout
comme indiqué :
@app.route('/logout') def logout(): session.pop('user',None) return redirect('/')
Nous avons déjà défini le href du bouton de déconnexion sur /logout
. Enregistrez donc toutes les modifications et redémarrez le serveur. Depuis la page d'accueil, cliquez sur Connexion et essayez de vous connecter avec une adresse e-mail et un mot de passe valides. Une fois connecté, cliquez sur Déconnexion dans l'accueil de l'utilisateur et vous devriez être déconnecté avec succès de l'application.