Estoy intentando usar Flask y la extensión Flask-Login para implementar la autenticación de usuario en una aplicación Flask. El objetivo es extraer la información de la cuenta de usuario de una base de datos y luego iniciar sesión en un usuario, pero me estoy atascado; sin embargo, lo he reducido a una parte en particular del comportamiento de inicio de sesión de Flask.Cómo implementar la devolución de llamada user_loader en Flask-Login
De acuerdo con Flask-Login documentation, necesito crear una función de "devolución de llamada" user_loader. El propósito real y la implementación de esta función me han confundido por unos días:
Deberá proporcionar una devolución de llamada user_loader. Esta devolución de llamada se usa para volver a cargar el objeto de usuario desde la ID de usuario almacenada en la sesión. Es debe tomar el identificador Unicode de un usuario y devolver el correspondiente objeto de usuario . Por ejemplo:
@login_manager.user_loader def load_user(userid): return User.get(userid)
Ahora, digo que quiero que el usuario introduzca un nombre y una contraseña en un formulario, compruebe contra una base de datos, e ingrese el usuario. La información de la base de datos funciona bien y no es un problema para mí.
Esta función de "devolución de llamada" quiere que se pase un ID de usuario #, y devuelva el objeto Usuario (cuyo contenido estoy cargando desde una base de datos). Pero realmente no obtengo lo que se supone que debe verificar/hacer, ya que las identificaciones de usuario son todas extraídas del mismo lugar de todos modos. Puedo 'ordenar' que la devolución de llamada funcione, pero parece desordenada/hackosa y llega a la base de datos con cada recurso que solicita el navegador. Realmente no quiero verificar mi base de datos para descargar favicon.ico con cada actualización de página, pero el matraz de inicio de sesión parece estar forzando esto.
Si no vuelvo a consultar la base de datos, entonces no tengo forma de devolver un objeto Usuario desde esta función. El objeto/clase del usuario se crea en la ruta del matraz para iniciar sesión y, por lo tanto, está fuera del alcance de la devolución de llamada.
Lo que no puedo entender es cómo pasar un objeto Usuario a esta función de devolución de llamada, sin tener que pulsar la base de datos cada vez. O, de lo contrario, averigüe cómo hacer esto de una manera más efectiva. Debo estar perdiendo algo fundamental, pero lo he estado mirando durante unos días, lanzando todo tipo de funciones y métodos, y nada está funcionando.
Aquí están los fragmentos relevantes de mi código de prueba. La clase de usuario:
class UserClass(UserMixin):
def __init__(self, name, id, active=True):
self.name = name
self.id = id
self.active = active
def is_active(self):
return self.active
La función que hice para devolver el objeto de usuario a la función del frasco de sesión user_loader devolución de llamada:
def check_db(userid):
# query database (again), just so we can pass an object to the callback
db_check = users_collection.find_one({ 'userid' : userid })
UserObject = UserClass(db_check['username'], userid, active=True)
if userObject.id == userid:
return UserObject
else:
return None
la 'devolución de llamada', que no entiendo por completo (debe volver el objeto de usuario, que se crea después de tirar de la base de datos):
@login_manager.user_loader
def load_user(id):
return check_db(id)
la ruta de acceso:
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST" and "username" in request.form:
username = request.form["username"]
# check MongoDB for the existence of the entered username
db_result = users_collection.find_one({ 'username' : username })
result_id = int(db_result['userid'])
# create User object/instance
User = UserClass(db_result['username'], result_id, active=True)
# if username entered matches database, log user in
if username == db_result['username']:
# log user in,
login_user(User)
return url_for("index"))
else:
flash("Invalid username.")
else:
flash(u"Invalid login.")
return render_template("login.html")
Mi código 'kinda' funciona, puedo iniciar y cerrar sesión, pero como dije, debe golpear la base de datos para absolutamente todo, porque tengo que proporcionar un objeto Usuario a la función de devolución de llamada en un espacio de nombre/alcance diferente desde donde tiene lugar el resto de la acción de inicio de sesión. Estoy bastante seguro de que estoy haciendo todo mal, pero no puedo entender cómo.
El código de ejemplo proporcionado por el matraz does it this way, pero esto solo funciona porque está extrayendo los objetos del usuario de un diccionario global codificado, no como en un escenario del mundo real como una base de datos, donde se debe verificar el DB y objetos de usuario creados después de el usuario ingresa sus credenciales de inicio de sesión. Y parece que no puedo encontrar ningún otro código de ejemplo que ilustre el uso de una base de datos con el nombre de usuario frasco.
¿Qué aquí se encuentra falta?
qué extraño. Su inicio de sesión() ni siquiera comprueba si hay alguna contraseña. – Houman
@hooman Esto fue solo para propósitos de ejemplo. –