Вход в учетную запись 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, который назначает несколько ролей в виде иерархии, работающей по сравнению с назначенной ролью. Я надеюсь, что это поможет кому-то бороться с тем, как все это связано. Мне еще многое предстоит узнать о том, где колба хранит вещи и когда они доступны в разных контекстах.