How to add your own decorator to the flask-admin panel?

Viewed 619

I am using Flask-Login for the login handling. In addition I wrote myself a decorator to keep views visible just for role=admin.

def admin_required(f):
    @wraps(f)
    def wrap(*args, **kwargs):
        if current_user.role.name == "admin":
            return f(*args, **kwargs)
        else:
            flash("You need to be an admin to view this page.")
            return redirect(url_for('home'))
    return wrap

I can use that decorator for my routes. But I don't know how to use this decorator for my flask-admin panel.

The Flask-SQLAlchemy Models were added to the flask-admin view like:

from flask_admin.contrib.sqla import ModelView
from flask_admin import Admin

admin = Admin(app, name='admin', template_mode='bootstrap3')

admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Role, db.session))

But I want if someone who is not an admin hits: 127.0.0.1:8000/admin do not get access and gets redirected to /home.

But I have no route for my /admin and when I implement one I do not know what html I should return?

Thank you

1 Answers

Use the built-in method is_accessible, by deafult, it returns True, which means that admin panel will be accessible by all, you can change it by overriding it like this:

class MyAdminViews(ModelView):

    def is_accessible(self):
        user = User.query.filter_by(role=current_user.role).first()
        res = user.role == "admin"
        return res

admin.add_view((MyAdminViews(User, db.session)))
admin.add_view((MyAdminViews(Post, db.session)))

Now, these admin views will be accessible if and only if the user possesses an admin role. Also, you might want to add a clause to make it accessible only when someone is logged in, else the browser will throw an internal server error. You can do it like this:

class MyAdminViews(ModelView):
    def is_accessible(self):
        if current_user.is_authenticated:
            user = User.query.filter_by(role=current_user.role).first()
            res = user.role == "admin"
            return res
Related