Flask Login и Principal - 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 знает, что пользователь вошел в систему, но по какой-то причине current_user несовместим.

Я где-то упустил важный момент конфигурации?


person fansonly    schedule 12.08.2013    source источник
comment
вы делаете что-нибудь с `static_url_path=''` в вашей инициализации Flask? Я столкнулся с аналогичной проблемой, см.: stackoverflow.com/questions/16627384/ Это сбивало с толку, поскольку сеанс и вход в систему выглядели нормально (пользователь мог войти в систему), но у меня всегда был анонимный пользователь при попадании в защищенную конечную точку   -  person craigb    schedule 19.09.2013


Ответы (2)


Я столкнулся с той же проблемой! Основная причина заключается в том, что и 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 зарегистрирован до Фласк-Войти. Тск тск! Вот что я сделал в своем бутстрапе:

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.

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

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

person Mark E. Haase    schedule 21.09.2013

Спасибо за это, вот связанное наблюдение на случай, если оно окажется полезным. Я боролся с аналогичной проблемой, когда роли пользователей не сохранялись в последующих запросах после входа в систему. Будучи новичком и играя с разными вещами, такими как flask-user (который у меня никогда не работал), и остановился на а) flask-principal и flask-login и б) flask-navigation вместо flask-nav.

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

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

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

  • Выше в порядке загрузки
  • Поскольку я еще не добавлял роли в свои модели, чтобы между пользователем и ролью существовала связь «многие ко многим», по моему невежеству я не осознавал, что Flask-Login нужно загружать роли в функцию @login_manager.user_loader, если роли, которых еще нет в модели. Вместо этого я назначил роли в представлении входа в систему после login_user(user) перед выдачей сигнала flask-principal.
  • С моим другим подходом роли были назначены, но забыты при следующем запросе. Этот пост дал мне подсказки, которые я искал. Это то, что я в итоге сделал - весь остальной код, связанный с Принципалом, такой же, как в документах и ​​выше.
#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, который назначает несколько ролей в виде иерархии, работающей вниз от назначенной роли. Я надеюсь, что что-то из этого поможет кому-то, кто борется с тем, как все это связано друг с другом. Мне еще многое предстоит узнать о том, где flask хранит вещи и когда они доступны в разных контекстах.

person Simon F    schedule 01.02.2019