Вход в учетную запись Flask и принципал - current_user является анонимным, хотя я вошел в систему

Я использую Flask Login и Principal для управления идентификацией и ролями. Мои потребности описаны прямо из документов. Мой код здесь:

@identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
    # Set the identity user object
    identity.user = current_user

    # Add the UserNeed to the identity
    if hasattr(current_user, 'get_id'):
        print 'current_user ' + str(current_user.get_id())
        identity.provides.add(UserNeed(current_user.get_id))

    # Assuming the User model has a list of roles, update the
    # identity with the roles that the user provides
    if hasattr(current_user, 'roles'):
        if current_user.roles:
            for role in current_user.roles:
                identity.provides.add(RoleNeed(role.name))

В моем коде входа я делаю это:

identity_changed.send(current_app._get_current_object(),
                                  identity=Identity(user.user_id)

При входе в систему сигнал срабатывает, как и ожидалось. При каждой последующей загрузке страницы current_user является анонимным и не имеет идентификатора пользователя, но все функции @login_required ведут себя так, как будто пользователь вошел в систему. Flask login знает, что пользователь вошел в систему, но по какой-то причине current_user не согласован.

Я что-то упустил где-то важную настройку?

1 ответ

Решение

Я столкнулся с той же проблемой! Основная причина заключается в том, что Flask-Login и Flask-Principal вызываются Flask на этапе "предварительной обработки" запроса в том порядке, в котором они были зарегистрированы в вашем приложении Flask. Если вы зарегистрируете Flask-Principal до регистрации Flask-Login, то @identity_loaded.connect_via(app) будет вызван раньше @login_manager.user_loader и, следовательно, current_user вернет анонимного пользователя.

Пример документации Flask-Principal показывает фрагмент кода, в котором Flask-Principal зарегистрирован до Flask-Login. Тск тск! Вот что я в итоге сделал в моей начальной загрузке:

login_manager = LoginManager()
login_manager.init_app(app)

# ...

principals = Principal(app) # This must be initialized after login_manager.

Затем в моем файле users.py:

@identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
    """ This function is called by Flask-Principal after a user logs in. """

    identity.user = current_user

    if isinstance(current_user, User):
        identity.provides.add(UserNeed(current_user.id))

    for permission in user.permissions:
        # Do permission-y stuff here.

Это решило проблему для меня.

Изменить: я представил отчет об ошибке в проект для документации.

Спасибо за это, вот связанное наблюдение в случае, если это полезно. Я боролся с подобной проблемой, когда роли пользователей не сохранялись в последующих запросах после входа в систему. Будучи новичком и играя с разными вещами, такими как флеш-пользователь (с которым я никогда не работал), и остановился на а) флеш-принципале и фляге-логине и б) флеш-навигации вместо фляги-нави.

Это так, я могу 1) легко контролировать, какие пункты меню появляются на основе Принципала, и 2) избегать генерации навигационной разметки вне шаблона (как меня всегда учили разделять логику и представление, и писать собственный рендерер меню для flask-nav). просто изменить окружающий HTML не кажется правильным, если я хочу изменить HTML позже). Я не смог найти способ перебирать объекты flask-nav или добавлять настраиваемые свойства к элементам nav, тогда как в flask-navigation я создаю настраиваемый Item, расширяющий Item of flask-navigation для добавления необходимых разрешений.

Задача, которую я также пытался решить, заключалась в том, чтобы иметь иерархию ролей, чтобы избежать необходимости добавлять сложные утверждения в мои представления (например, администратор также редактор, также пользователь, также анонимный пользователь и т. Д.) Неистово погуглив, я не смог найти любое понятие иерархии, как это. Я также не хочу, чтобы в моей модели было назначено несколько ролей.

Мои ошибки были:

  • Выше в порядке загрузки
  • Поскольку я еще не помещал роли в свои модели, так что между Пользователем и Ролью существовало много-много отношений, в своем невежестве я не осознавал, что Flask-Login необходимо загружать роли в функцию @login_manager.user_loader, если роли еще не были в модели. Вместо этого я назначил роли в представлении входа в систему после login_user (пользователь) до выдачи основного сигнала фляги.
  • При моем другом подходе роли были назначены, но забыты при следующем запросе. Этот пост дал мне подсказки, которые я искал. Это то, что я в итоге сделал - весь остальной код, связанный с Принципалом, такой же, как в документации и выше.
#CAVEATS - still learning Flask so this may not be the right approach and it is still a W.I.P.
#added a  kind of hierarchy order field to User to drive multiple roles in Permissions
#with this model I only have to assign one role to a user

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(50), unique=True)
    description = db.Column(db.String(200))
    hierarchy_order = db.Column(db.Integer)
    internal = db.Column(db.Boolean) # this is only so I can identify registered users and internal users
    users = db.relationship('User', backref='role',lazy='dynamic')

    def __repr__(self):
        return '<Role: {}>'.format(self.name)

# changed common flask-login example @login_manager.user_loader as follows

@login_manager.user_loader
def load_user(user_id):
    user = User.query.get(int(user_id))
    #work out what roles are below current role
    permissable_roles = Role.query.filter(Role.hierarchy_order<=user.role.hierarchy_order).all()
    user.roles = permissable_roles
    return user

Мне бы очень хотелось, чтобы этот подход был общим соглашением, но я думаю, что застрял с наличием цикла в @login_manager.user_loader, который назначает несколько ролей в виде иерархии, работающей по сравнению с назначенной ролью. Я надеюсь, что это поможет кому-то бороться с тем, как все это связано. Мне еще многое предстоит узнать о том, где колба хранит вещи и когда они доступны в разных контекстах.

Другие вопросы по тегам