简体   繁体   中英

Flask-Admin permissions for adding user with specific role

I use Flask-Admin and Flask-Security to implement admin panel for my Python application. Here are the models for User and for Role :

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

    def __str__(self):
        return self.name


class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(255), unique=True, index=True)
    password = db.Column(db.String(255))
    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

    def __str__(self):
        return self.username

I created a sqla.ModelView for User available only for users with roles "admin" and "superadmin", so such users can create new users using this view. How can I make only users with role "superadmin" can create users with roles "superadmin" and "admin"? In other words I want to specify which of the variants are available for users with different roles: https://imgur.com/a/GdhUS2Y .

To do that you will have to customize a few things.

I would suggest the following:

add this method in your User model that checks if a user has a certain role:

def has_role(self, role):
    # db is your database session. 
    query = db.query(Role).filter(Role.name == role).first()
    if query:
        if query.name in self.roles:
            return True
    return False

Now you have to customize the roles that are being displayed when a user tries to create a new user. To achieve that, you will need to change the definition of the roles field. To achieve that, you will need to override the flask-admin scaffold_form() method.

from flask_admin.contrib.sqla.fields import QuerySelectMultipleField
from flask_security import current_user
from flask_admin.form import Select2Widget
def scaffold_form(self):
    form_class = super(YourUserAdminClass, self).scaffold_form()
    role_filter = Role.name == Role.name if current_user.has_role('superadmin') else Role.name.notin_('superadmin', 'admin')
    form_class.roles = QuerySelectMultipleField(
            query_factory=lambda: self.session.query(Role).filter(role_filter),
            allow_blank,
            blank_text='Select Role',
            widget=Select2Widget(multiple=False) # change this to True if you allow multiple roles
        )

The code above will render the dropdown with the roles depending on the role that the current_user have (using the has_role() method in the filter

Although the answer by @shifloni provides a concise idea of what's need to be done, as per what I have observed, I think it's incomplete. It's because of the fact that if current_user.has_role('superadmin') throws error during app initialization as current_user is available only when the code is executed in a request context. This is what worked for me:

class ViewForCreatingAdminAndOperators(sqla.ModelView):
    def _run_view(self, fn, *args, **kwargs):
        if current_user.has_role('admin'):
            self.role_filter = Role.name.in_(['operator'])
        else:
            self.role_filter = Role.name.in_(['superadmin', 'admin', 'operator'])

        return fn(self, *args, **kwargs)

    def scaffold_form(self):
        form = super(ViewForCreatingAdminUsers, self).scaffold_form()
        form.roles = QuerySelectMultipleField(
            query_factory=lambda: self.session.query(Role).filter(self.role_filter),
            widget=Select2Widget(multiple=False)  # change this to True if you allow multiple roles
        )
        return form

_run_view func is always called in a request context, so whenever we click to create a form, that func is called and we have the role_filter available.

PS Use case as per above code was that admin should be able to create only operator .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM