Как реализовать обратный вызов user_loader в Flask-Login

Я пытаюсь использовать Flask и расширение Flask-Loginдля реализации пользователя. аутентификация в приложении Flask. Цель состоит в том, чтобы извлечь информацию об учетной записи пользователя из базы данных, а затем войти в систему пользователя, но я застрял; однако я сузил его до определенной части поведения Flask-Login.

Согласно документации Flask-Login, мне нужно создать функцию обратного вызова user_loader. Фактическая цель и реализация этой функции уже несколько дней смущают меня:

Вам нужно будет обеспечить обратный вызов user_loader. Этот обратный вызов используется для перезагрузки объекта пользователя из идентификатора пользователя, сохраненного в сеансе. Это должен принимать Unicode ID пользователя и возвращать соответствующий пользовательский объект. Например:

@login_manager.user_loader
деф load_user (идентификатор пользователя):
вернуть пользователя.получить (идентификатор пользователя)

Теперь предположим, что я хочу, чтобы пользователь ввел имя и пароль в форму, сверился с базой данных и зарегистрировался. Материал базы данных работает нормально и не является проблемой для меня.

Эта функция «обратного вызова» хочет получить идентификатор пользователя # и вернуть объект «Пользователь» (содержимое которого я загружаю из базы данных). Но я действительно не понимаю, что он должен проверять/делать, поскольку идентификаторы пользователей все равно берутся из одного и того же места. Я могу «вроде» заставить обратный вызов работать, но он кажется грязным/хакерским, и он попадает в базу данных с каждым ресурсом, который запрашивает браузер. Я действительно не хочу проверять свою базу данных, чтобы загружать favicon.ico при каждом обновлении страницы, но flask-login, похоже, заставляет это делать.

Если я снова не проверю базу данных, у меня не будет возможности вернуть объект пользователя из этой функции. Объект/класс User создается в маршруте flask для входа в систему и, таким образом, выходит за рамки обратного вызова.

Чего я не могу понять, так это того, как передать объект User в эту функцию обратного вызова, не обращаясь каждый раз к базе данных. Или, в противном случае, выяснить, как сделать это более эффективным способом. Должно быть, я упускаю что-то фундаментальное, но я смотрю на это уже несколько дней, бросая на него всевозможные функции и методы, и ничего не получается.

Вот соответствующие фрагменты кода моего теста.Класс User:

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

Функция, которую я сделал для возврата объекта пользователя в функцию обратного вызова user_loader Flask-Login:

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

«Обратный вызов», который я не совсем понимаю (должен возвращать объект пользователя, который создается после извлечение из базы данных):

@login_manager.user_loader
def load_user(id):
     return check_db(id)

Маршрут входа в систему:

@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")

Мой код вроде как работает, я могу войти и выйти, но, как я уже сказал, он должен попадать в базу данных абсолютно для всего, потому что я должен предоставить пользователя объект для функции обратного вызова в другом пространстве имен/области, где происходит остальная часть действия входа. Я почти уверен, что делаю все неправильно, но я не могу понять, как это сделать.

Пример кода, предоставленный flask-login , делает это таким образом, но это работает только потому, что он извлекает объекты User из глобального жестко запрограммированного словаря, а не как в реальном сценарии, таком как база данных, где БД должна быть проверена, а объекты пользователя должны быть созданы после ввода пользователем своих учетных данных для входа. И я не могу найти другого примера кода, иллюстрирующего использование базы данных с flask-login.

Чего здесь не хватает?

28
задан Mike 29 August 2017 в 23:12
поделиться