flask-security add_role_to_user не принимает имя пользователя

при попытке назначить роль пользователю, как заставить ее работать с именем пользователя вместо электронной почты?

Следующие работы:

user_datastore.add_role_to_user('[email protected]', 'site-admin')

это не работает:

user_datastore.add_role_to_user('admin', 'site-admin')

ошибка, которую он дает:

AttributeError: 'NoneType' object has no attribute 'roles'

моя модель выглядит так:

roles_users = db.Table('users_to_roles',
    db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
    db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))


class User(db.Model, UserMixin):
  id = db.Column(db.Integer, primary_key=True)
  username = db.Column(db.String(16), unique=True)
  email = db.Column(db.String(256), unique=True)
  password = db.Column(db.String(255))
  active = db.Column(db.Boolean())
  confirmed_at = db.Column(db.DateTime())
  roles = db.relationship('Role', secondary=roles_users,
                        backref=db.backref('users', lazy='dynamic'))

person Simply Seth    schedule 10.04.2018    source источник


Ответы (3)


Если вы посмотрите на исходный код, https://github.com/mattupstate/flask-security/blob/develop/flask_security/datastore.py add_role_to_user вызывает метод

def add_role_to_user(self, user, role):
        """Adds a role to a user.
        :param user: The user to manipulate
        :param role: The role to add to the user
        """
        user, role = self._prepare_role_modify_args(user, role)
        if role not in user.roles:
            user.roles.append(role)
            self.put(user)
            return True
        return False

который, в свою очередь, вызывает

def _prepare_role_modify_args(self, user, role):
        if isinstance(user, string_types):
            user = self.find_user(email=user)
        if isinstance(role, string_types):
            role = self.find_role(role)
        return user, role

Этот метод извлекает объект пользователя с помощью электронной почты. Если вам действительно нужно получить по имени пользователя (и убедиться, что оно уникально) вместо электронной почты, вы можете разветвить flask-security и изменить строку (строка 121) с

user = self.find_user(email=user)

to

user = self.find_user(username=user)

затем вы переустанавливаете flask-security из своего репо (удалите flask-security, затем установите)

pip install git+https://github.com/your_repo/flask-security

Я лично сделал много настроек и работает нормально. Обратите внимание, что вам нужно будет использовать имя пользователя каждый раз, когда вам нужно изменить роль.

person Moses N. Njenga    schedule 11.04.2018
comment
Нет необходимости изменять исходный код. Просто используйте мое решение ниже: Получите пользовательский объект, затем добавьте роль к пользовательскому объекту. Как вы видите в _prepare_role_modify_args выше, если вы передаете ему пользовательский объект, ему не нужно извлекать пользователя. Судя по всему, ОП не смог заставить его работать, поэтому он дал мне -1. - person GAEfan; 11.04.2018

используйте 3 таблицы с веб-сайта flask-security, таблица ролей не включена в ваш пример. Я не включаю здесь «каждый нюанс», а только ключевые части кода. Я переименовал таблицу User в Users, потому что некоторые базы данных имеют конфликты имен. поскольку все, что вы предоставляете, - это запрос, который вы, очевидно, можете запросить по имени пользователя или электронной почте (я использую электронную почту).

в вашем ____init____.py (или app.py)

from flask_security import Security, SQLAlchemyUserDatastore


def create_app():
    user_datastore = SQLAlchemyUserDatastore(db, Users, Role)
    security = Security(app, user_datastore,
                        confirm_register_form=ExtendedConfirmRegisterForm)

    return app

модели.py

roles_users = db.Table('roles_users',
        db.Column('user_id', db.Integer(), db.ForeignKey('users.id')),
        db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))


class Role(db.Model, RoleMixin):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(80), unique=True)
    description = db.Column(db.String(255))


class Users(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(50), unique=True)
    name = db.Column(db.String(30))
    password = db.Column(db.String(255))
    about = db.Column(db.String(255))
    last_login_at = db.Column(db.DateTime())
    current_login_at = db.Column(db.DateTime())
    last_login_ip = db.Column(db.String(100))
    current_login_ip = db.Column(db.String(100))
    login_count = db.Column(db.Integer)
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())

    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

просмотры.py

from app import db, create_app

app = create_app()
app.app_context().push()
security = app.extensions.get('security')

в вашем views.py запросите пользователя и роль

u = Users.query.filter_by(email='[email protected]').first()
r = Role.query.filter_by(name='test').first()
security.datastore.add_role_to_user(u, r)
db.session.commit()
person Jeff Bluemel    schedule 29.04.2018

Вам нужно либо передать add_role_to_user адрес электронной почты в виде строки, либо сам объект пользователя. Итак, вы можете получить пользователя по имени пользователя, а затем отправить этот пользовательский объект в add_role_to_user:

user_datastore.add_role_to_user(my_user, 'site-admin')
person GAEfan    schedule 10.04.2018
comment
пробовал: auth_user = user_datastore.find_user(username='admin') потом user_datastore.add_role_to_user(auth_user,'site-admin') ... не получилось - person Simply Seth; 10.04.2018
comment
Зарегистрируйтесь auth_user, чтобы убедиться, что вы нашли реального пользователя - person GAEfan; 10.04.2018
comment
Кроме того, вам может потребоваться добавить имя пользователя в качестве действительного логина: app.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = ('username','email') - person GAEfan; 10.04.2018