Je veux créer une webapp simple dans le cadre de mon activité d'apprentissage. Webapp est censé demander à l'utilisateur de saisir son email_id s'il rencontre un visiteur pour la première fois, il se souvient de l'utilisateur via un cookie et le connecte automatiquement pour exécuter les fonctions.
C'est la première fois que je crée une application Web basée sur l'utilisateur. J'ai une impression bleue en tête, mais je n'arrive pas à comprendre comment la mettre en œuvre. Je suis principalement confus quant à la manière de collecter les cookies utilisateur. J'ai examiné divers didacticiels et flask_login mais je pense que ce que je veux implémenter est beaucoup plus simple par rapport à ce que flask_login implémente.
J'ai également essayé d'utiliser flask.session
mais c'était un peu difficile à comprendre et je me suis retrouvé avec une implémentation imparfaite.
Voici ce que j'ai jusqu'à présent (c'est rudimentaire et destiné à communiquer mon cas d'utilisation):
from flask import render_template, request, redirect, url_for
@app.route("/", methods= ["GET"])
def first_page():
cookie = response.headers['cookie']
if database.lookup(cookie):
user = database.get(cookie) # it returns user_email related to that cookie id
else:
return redirect_url(url_for('login'))
data = generateSomeData() # some function
return redirect(url_for('do_that'), user_id, data, stats)
@app.route('/do_that', methods =['GET'])
def do_that(user_id):
return render_template('interface.html', user_id, stats,data) # it uses Jinja template
@app.route('/submit', methods =["GET"])
def submit():
# i want to get all the information here
user_id = request.form['user_id']# some data
answer = request.form['answer'] # some response to be recorded
data = request.form['data'] # same data that I passed in do_that to keep
database.update(data,answer,user_id)
return redirect(url_for('/do_that'))
@app.route('/login', methods=['GET'])
def login():
return render_template('login.html')
@app.route('/loggedIn', methods =['GET'])
def loggedIn():
cookie = response.headers['cookie']
user_email = response.form['user_email']
database.insert(cookie, user_email)
return redirect(url_for('first_page'))
Vous pouvez accéder aux cookies de demande via request.cookies
dictionary et définissez les cookies à l'aide de make_response
ou simplement stocker le résultat de l'appel de render_template
dans une variable puis appelant set_cookie
sur l'objet réponse :
@app.route("/")
def home():
user_id = request.cookies.get('YourSessionCookie')
if user_id:
user = database.get(user_id)
if user:
# Success!
return render_template('welcome.html', user=user)
else:
return redirect(url_for('login'))
else:
return redirect(url_for('login'))
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
# You should really validate that these fields
# are provided, rather than displaying an ugly
# error message, but for the sake of a simple
# example we'll just assume they are provided
user_name = request.form["name"]
password = request.form["password"]
user = db.find_by_name_and_password(user_name, password)
if not user:
# Again, throwing an error is not a user-friendly
# way of handling this, but this is just an example
raise ValueError("Invalid username or password supplied")
# Note we don't *return* the response immediately
response = redirect(url_for("do_that"))
response.set_cookie('YourSessionCookie', user.id)
return response
@app.route("/do-that")
def do_that():
user_id = request.cookies.get('YourSessionCookie')
if user_id:
user = database.get(user_id)
if user:
# Success!
return render_template('do_that.html', user=user)
else:
return redirect(url_for('login'))
else:
return redirect(url_for('login'))
Maintenant, vous remarquerez qu'il y a beaucoup de passe-partout dans les home
et do_that
méthodes, toutes liées à la connexion. Vous pouvez éviter cela en écrivant votre propre décorateur (voir Qu'est-ce qu'un décorateur si vous voulez en savoir plus à leur sujet):
from functools import wraps
from flask import flash
def login_required(function_to_protect):
@wraps(function_to_protect)
def wrapper(*args, **kwargs):
user_id = request.cookies.get('YourSessionCookie')
if user_id:
user = database.get(user_id)
if user:
# Success!
return function_to_protect(*args, **kwargs)
else:
flash("Session exists, but user does not exist (anymore)")
return redirect(url_for('login'))
else:
flash("Please log in")
return redirect(url_for('login'))
return wrapper
Ensuite, votre home
et do_that
les méthodes deviennent beaucoup plus courtes:
# Note that login_required needs to come before app.route
# Because decorators are applied from closest to furthest
# and we don't want to route and then check login status
@app.route("/")
@login_required
def home():
# For bonus points we *could* store the user
# in a thread-local so we don't have to hit
# the database again (and we get rid of *this* boilerplate too).
user = database.get(request.cookies['YourSessionCookie'])
return render_template('welcome.html', user=user)
@app.route("/do-that")
@login_required
def do_that():
user = database.get(request.cookies['YourSessionCookie'])
return render_template('welcome.html', user=user)
Si vous n'avez pas besoin de votre cookie pour avoir un nom particulier, je vous recommande d'utiliser flask.session
car il contient déjà beaucoup de subtilités (il est signé de sorte qu'il ne peut pas être falsifié, peut être défini sur HTTP uniquement, etc.). Que DRYs notre login_required
décorateur encore plus:
# You have to set the secret key for sessions to work
# Make sure you keep this secret
app.secret_key = 'something simple for now'
from flask import flash, session
def login_required(function_to_protect):
@wraps(function_to_protect)
def wrapper(*args, **kwargs):
user_id = session.get('user_id')
if user_id:
user = database.get(user_id)
if user:
# Success!
return function_to_protect(*args, **kwargs)
else:
flash("Session exists, but user does not exist (anymore)")
return redirect(url_for('login'))
else:
flash("Please log in")
return redirect(url_for('login'))
Et puis vos méthodes individuelles peuvent obtenir l'utilisateur via:
user = database.get(session['user_id'])