I want to control who can access admin pages on my flask application.
I've been trying to overwrite the flask_admin.ModelView's methods, 'is_accessible' and 'inaccessible_callback' to handle the situation.
This is the AdminView class I'm creating:
class AdminView(ModelView):
def is_accessible(self):
return current_user.admin
def inaccessible_callback(self, name, **kwargs):
# redirect to login page if user doesn't have access
return redirect(url_for('auth.login', next=request.url))
and the model:
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True)
email = db.Column(db.String(120), unique=True)
password_hash = db.Column(db.String(128))
admin = db.Column(db.Boolean, default=False)
def __init__(self, username=None, email=None, password=None):
self.username = username
self.email = email
self.password_hash = password_hash
self.admin = admin
and the AdminView initialization:
def init_admin(admin):
from app.models import User
admin.add_view(AdminView(User, db.session))
which is called in the application factory:
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
if test_config is None:
# load the isntance config, if it exists, when not testing
app.config.from_object(Config)
else:
# load the test config passed in
app.config.from_object(test_config)
db.init_app(app)
migrate = Migrate(app, db)
login_manager.init_app(app)
mail.init_app(app)
bootstrap.init_app(app)
admin = Admin(app, name='app', template_mode='bootstrap3')
from app.auth import auth_bp
app.register_blueprint(auth_bp)
from app.tables import tables_bp
app.register_blueprint(tables_bp)
init_admin(admin)
try:
os.makedirs(app.instance_path)
except OSError:
pass
return app
When I login with a user that has it's admin
attribute set to True
it returns the correct admin page with the User model ready to be used. When I login with a user that has a false admin
attribute, it still shows the admin page, without the User model attached. I would rather that it redirect them to a login page, with a warning that they are forbidden from that page.
I figured out how to get this to work thanks to a youtube video!
Check it out for a more in-depth explanation!
The issue was that the '/admin' page is loaded by flask_admin.AdminIndexView
Therefore I had to create my own child class of AdminIndexView
and set this as the index_view
parameter when initializing Admin()
Here is the updated code: I added a MyIndexView class to my admin file:
# ...
from flask_admin import AdminIndexView
# ...
class MyIndexView(AdminIndexView):
def is_accessible(self):
return current_user.admin
def inaccessible_callback(self, name, **kwargs):
# redirect to login page if user doesn't have access
return redirect(url_for('auth.login', next=request.url))
And then I set the index_view
parameter in my application factory
# ...
from app.admin import AdminView, MyIndexView
# ...
admin = Admin(app, name='app', template_mode='bootstrap3',
index_view=MyIndexView())
# ...
It now works perfectly!