web-dev-qa-db-fra.com

Comment sécuriser le panneau d'administration de flask avec flask-security

Je cherche à sécuriser l'API Web créée à l'aide de Flask et intégrée à flask-admin Pour fournir une interface d'administration. J'ai recherché et trouvé que flask-admin possède un panneau d'administration à /admin Et par défaut, tout le monde peut y accéder. Il ne fournit aucun système d'authentification et est complètement ouvert (sans aucune sécurité) car ils ne supposaient pas ce qui serait utilisé pour assurer la sécurité. Cette API doit être utilisée en production, nous ne pouvons donc pas avoir de route /admin ouverte pour tout le monde qui accède à l'URL. Une authentification appropriée est nécessaire.

Dans views.py, Je ne peux pas simplement mettre la route /admin Et fournir une authentification via le décorateur car cela écraserait la route existante déjà créée par flask-admin, Ce qui provoquerait un Erreur.

D'autres recherches montrent qu'il existe deux modules flask-admin Et flask-security. Je sais que flask-admin A la méthode is_accessible Pour le sécuriser, mais il ne fournit pas beaucoup de fonctionnalités qui sont fournies par flask-security.

Je n'ai trouvé aucune méthode pour sécuriser le point final /admin Ainsi que tous les autres points finaux commençant par /admin Tels que /admin/<something>.

Je cherche spécifiquement à faire cette tâche avec flask-security. Si ce n'est pas possible, veuillez suggérer des alternatives.

PS: Je sais que je peux verrouiller ngnix lui-même, mais ce serait la dernière option. Si je peux avoir un système d'authentification via flask-security Ce serait bien.

20
Sanyam Khurana

Vous devriez vérifier le projet Flask-Security-Admin , je pense qu'il couvre assez clairement ce que vous recherchez.

Tiré directement du lien ci-dessus:

  • Lors de votre première visite sur la page d'accueil de l'application, vous serez invité à vous connecter, grâce à Flask-Security.
  • Si vous vous connectez avec [email protected] et password = password, vous aurez le rôle "utilisateur final".
  • Si vous vous connectez avec [email protected] et password = password, vous aurez le rôle "admin".
  • Les deux rôles sont autorisés à accéder à la page d'accueil.
  • Les deux rôles sont autorisés à accéder à la page/admin. Cependant, à moins que vous n'ayez le rôle "admin", vous ne verrez pas les onglets pour l'administration des utilisateurs et des rôles sur cette page.
  • Seul le rôle admin est autorisé à accéder aux sous-pages de la page/admin telles que/admin/userview. Sinon, vous obtiendrez une réponse "interdite".
  • Notez que lors de l'édition d'un utilisateur, les noms des rôles sont automatiquement renseignés grâce à Flask-Admin.
  • Vous pouvez ajouter et modifier des utilisateurs et des rôles. Les utilisateurs résultants pourront se connecter (sauf si vous définissez active = false) et, s'ils ont le rôle "admin", ils pourront effectuer l'administration.

Le code correspondant se trouve dans main.py et est clairement commenté pour expliquer comment reproduire le processus de sécurisation du panneau d'administration de flask à l'aide de flask-security.

La pièce la plus fondamentale et la plus pertinente pour vous est la suivante (ligne 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')

J'espère que ceci est utile.

9
RamiMac

Étant donné qu'il s'agit du premier résultat de la recherche google "flask-security secure admin", et qu'il n'y a pas encore de solution prête à l'emploi, je pense que je peux y contribuer.

Une question similaire a été posée sur le projet flask-admin Issue List et un exemple simple utilisant flask-login et mogodb est fourni ici .

J'ai fait un exemple en utilisant SQLAchemy pour une base de données sqlite et flask-security. Voir l'exemple flask app ci-dessous:

 #!/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)

Veuillez vous référer aux documents flask-security pour savoir comment personnaliser la page de connexion .

J'espère que cela t'aides.

12
guilhermerama

J'utilise la réponse de @ RamiMac pour toutes les sous-vues, mais pour l'index (par défaut /admin), J'utilise cette méthode, re-wrap la méthode avec un rôle admin requis pour afficher.

@app.before_first_request
def 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()

Dans mon projet, cela va directement après tous mes Flask-Admin code, qui est lui-même dans son propre script de démarrage, custom_flaskadmin.py.

3
seaders

Il y a une section sur la sécurité dans la documentation Flask-Admin: http://flask-admin.readthedocs.io/en/latest/introduction/#authorization-permissions

1
Joes