I'm looking to secure Web API made using Flask and integrated with flask-admin
to provide an admin interface. I searched and found that flask-admin has an admin panel at /admin
and by default anyone can have access to it. It provides no authentication system and completely open (without any security) since they didn't assume what would be used to provide security. This API has to be used in production, so we can't have an open /admin
route for everyone hitting the url. Proper authentication is needed.
In views.py
I can't simply put the /admin
route and provide authentication through decorator as that would be over-writing the existing route already created by flask-admin
so that would cause an error.
Further research shows that there are two modules flask-admin
and flask-security
. I know that flask-admin
has is_accessible
method to secure it, but it doesn't provide much functionality which is provided by flask-security
.
I've not found any method there to secure the end-point /admin
plus all other end-points beginning with /admin
such as /admin/<something>
.
I'm looking specifically to do this task with flask-security. If it's not possible, please suggest alternatives.
PS: I know I can lock ngnix
itself, but that would be the last option. If I can have an authentication system through flask-security
that would be good.
You should see a url http:127.0. 0.1:5000 provided to you in your terminal, open your preferred browser and navigate to that url or localhost:5000. You should see the login screen of the Admin Dashboard. To be able to access the main page/dashboard, you need to create an account.
Introduction. Flask-Admin is a batteries-included, simple-to-use Flask extension that lets you add admin interfaces to Flask applications. It is inspired by the django-admin package, but implemented in such a way that the developer has total control of the look, feel and functionality of the resulting application.
Flask-Security allows you to quickly add common security mechanisms to your Flask application. They include: Session based authentication. Role management.
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 os import os.path as op from flask import Flask, render_template, url_for, request from flask_sqlalchemy import SQLAlchemy from sqlalchemy.event import listens_for from flask.ext.security import current_user, login_required, RoleMixin, Security, SQLAlchemyUserDatastore, UserMixin from flask_admin import Admin, AdminIndexView from flask_admin.contrib import sqla # Create application app = Flask(__name__) # Create dummy secrety key so we can use sessions app.config['SECRET_KEY'] = '123456790' # Create in-memory database app.config['DATABASE_FILE'] = 'sample_db.sqlite' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE'] app.config['SQLALCHEMY_ECHO'] = True db = SQLAlchemy(app) # Create directory for file fields to use file_path = op.join(op.dirname(__file__), 'static/files') # flask-security models roles_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 Security user_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='[email protected]', 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.name class 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 views admin.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 [email protected] and password=password, you'll have the "end-user" role.
- If you log in with [email protected] 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" role def is_accessible(self): return current_user.has_role('admin')
I hope this is helpful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With