How to secure the flask-admin panel with flask-security How to secure the flask-admin panel with flask-security flask flask

How to secure the flask-admin panel with flask-security


Since this is the first result for the "flask-security secure admin" google search, and there is no out-of-the-box solution yet, I think I can contribute.

A similiar question was asked on the flask-admin project Issue List and a simple example using flask-login and mogodb is provided here.

I made an example using SQLAchemy for a sqlite database and flask-security. See the sample flask app below:

 #!/usr/bin/env python# -*- coding: utf-8 -*-import osimport os.path as opfrom flask import Flask, render_template, url_for, requestfrom flask_sqlalchemy import SQLAlchemyfrom sqlalchemy.event import listens_forfrom flask.ext.security import current_user, login_required, RoleMixin, Security, SQLAlchemyUserDatastore, UserMixinfrom flask_admin import Admin, AdminIndexViewfrom flask_admin.contrib import sqla# Create applicationapp = Flask(__name__)# Create dummy secrety key so we can use sessionsapp.config['SECRET_KEY'] = '123456790'# Create in-memory databaseapp.config['DATABASE_FILE'] = 'sample_db.sqlite'app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']app.config['SQLALCHEMY_ECHO'] = Truedb = SQLAlchemy(app)# Create directory for file fields to usefile_path = op.join(op.dirname(__file__), 'static/files')# flask-security modelsroles_users = db.Table('roles_users',        db.Column('user_id', db.Integer(), db.ForeignKey('user.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 User(db.Model, UserMixin):    id = db.Column(db.Integer, primary_key=True)    email = db.Column(db.String(255), 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'))# Create Securityuser_datastore = SQLAlchemyUserDatastore(db, User, Role)security = Security(app, user_datastore)# Only needed on first execution to create first user#@app.before_first_request#def create_user():#    db.create_all()#    user_datastore.create_user(email='yourmail@mail.com', password='pass')#    db.session.commit()class AnyModel(db.Model):    id = db.Column(db.Integer, primary_key=True)    name = db.Column(db.Unicode(64))    def __unicode__(self):        return self.nameclass MyAdminIndexView(AdminIndexView):    def is_accessible(self):        return current_user.is_authenticated() # This does the trick rendering the view only if the user is authenticated# Create admin. In this block you pass your custom admin index view to your admin area admin = Admin(app, 'Admin Area', template_mode='bootstrap3', index_view=MyAdminIndexView())# Add viewsadmin.add_view(sqla.ModelView(AnyModel, db.session)) # To acess the logout just type the route /logout on browser. That redirects you to the index@login_required@app.route('/login')def login():    return redirect('/admin')@app.route('/')def index():    return render_template('index.html')if __name__ == '__main__':    # Build sample db on the fly, if one does not exist yet.    db.create_all()     app.run(debug=True)

Please refer to the flask-security docs to learn how to customize the login page.

Hope this helps.


You should check out the Flask-Security-Admin project, I think it covers pretty clearly what you are looking for.

Taken directly from the link above:

  • When you first visit the app's home page, you'll be prompted to log in, thanks to Flask-Security.
  • If you log in with username=someone@example.com and password=password, you'll have the "end-user" role.
  • If you log in with username=admin@example.com and password=password, you'll have the "admin" role.
  • Either role is permitted to access the home page.
  • Either role is permitted to access the /admin page. However, unless you have the "admin" role, you won't see the tabs for administration of users and roles on this page.
  • Only the admin role is permitted to access sub-pages of /admin page such as /admin/userview. Otherwise, you'll get a "forbidden" response.
  • Note that, when editing a user, the names of roles are automatically populated thanks to Flask-Admin.
  • You can add and edit users and roles. The resulting users will be able to log in (unless you set active=false) and, if they have the "admin" role, will be able to perform administration.

The relevant code is located in main.py, and is clearly commented to explain how to replicate the process of securing the flask-admin panel using flask-security.

The most basic, relevant piece to you is the following (line 152-):

# Prevent administration of Users unless the currently logged-in user has the "admin" roledef is_accessible(self):    return current_user.has_role('admin')

I hope this is helpful.


I use @RamiMac's answer for all sub-views, but for the index one (by default /admin), I use this method, re-wrap the method with an admin role required to view.

@app.before_first_requestdef restrict_admin_url():    endpoint = 'admin.index'    url = url_for(endpoint)    admin_index = app.view_functions.pop(endpoint)    @app.route(url, endpoint=endpoint)    @roles_required('admin')    def secure_admin_index():        return admin_index()

In my project, this goes directly after all my Flask-Admin code, which is itself in its own startup script, custom_flaskadmin.py.