2015-06-27 19 views
15

Sto cercando di proteggere l'API Web realizzata con Flask e integrata con flask-admin per fornire un'interfaccia di amministrazione. Ho cercato e trovato che flask-admin ha un pannello di amministrazione a /admin e per impostazione predefinita chiunque può accedervi. Non fornisce alcun sistema di autenticazione e completamente aperto (senza alcuna sicurezza) in quanto non presuppone quale sarebbe stato usato per fornire sicurezza. Questa API deve essere utilizzata in produzione, quindi non è possibile avere una route aperta /admin per tutti che eseguono l'url. È necessaria l'autenticazione corretta.Come proteggere il pannello admin-flask con la sicurezza del pallone

In views.py Non posso semplicemente inserire il percorso /admin e fornire l'autenticazione tramite decoratore in quanto ciò significherebbe sovrascrivere il percorso esistente già creato da flask-admin in modo da causare un errore.

Ulteriori ricerche mostrano che ci sono due moduli flask-admin e flask-security. So che flask-admin ha il metodo is_accessible per proteggerlo, ma non fornisce molte funzionalità fornite da flask-security.

Non ho trovato alcun metodo lì per fissare il punto finale /admin oltre a tutti gli altri end-point che iniziano con /admin come /admin/<something>.

Sto cercando in particolare di eseguire questa operazione con la sicurezza dei flaconi. Se non è possibile, si prega di suggerire alternative.

PS: so che posso bloccare ngnix stesso, ma quella sarebbe l'ultima opzione. Se posso avere un sistema di autenticazione attraverso flask-security sarebbe bello.

+1

Il meccanismo di autenticazione di Flask-Security (tramite Flask-Login) controlla il valore di ritorno di "current_user.is_authenticated()'. Restituire questo (eventualmente combinato con qualche tipo di controllo di ruolo/permesso) nell'implementazione di 'is_accessible' dovrebbe darti la possibilità di usare la protezione di Flask-Security all'interno di Flask-Admin. – jonafato

risposta

4

Si dovrebbe verificare il progetto Flask-Security-Admin, penso che copre abbastanza chiaramente ciò che si sta cercando.

prese direttamente dal link qui sopra:

  • La prima volta che visita la home page del app, ti verrà richiesto di accedere, grazie a Flask-Security.
  • Se si accede con [email protected] e password = password, si avrà il ruolo di "utente finale".
  • Se si accede con [email protected] e password = password, si avrà il ruolo di "admin".
  • Entrambi i ruoli sono autorizzati ad accedere alla pagina iniziale.
  • Entrambi i ruoli sono autorizzati ad accedere alla pagina/admin. Tuttavia, a meno che tu non abbia il ruolo "admin", non vedrai le schede per l'amministrazione di utenti e ruoli in questa pagina.
  • Solo il ruolo di amministratore è autorizzato ad accedere alle pagine secondarie della pagina/admin come/admin/userview. Altrimenti, riceverai una risposta "proibita".
  • Nota che, quando si modifica un utente, i nomi dei ruoli vengono popolati automaticamente grazie a Flask-Admin.
  • È possibile aggiungere e modificare utenti e ruoli. Gli utenti risultanti saranno in grado di accedere (a meno che non si imposti active = false) e, se hanno il ruolo "admin", saranno in grado di eseguire l'amministrazione.

Il codice in questione si trova in main.py, ed è chiaramente commentato a spiegare come replicare il processo di protezione del pannello di pallone-admin utilizzando pallone-sicurezza.

Il più semplice, pezzo relativo al sistema è il seguente (linea 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') 

Spero che questo sia utile.

+1

Grazie! Dopo ulteriori ricerche e scavi, ho potuto farlo funzionare. –

+0

Grazie per aver fornito questo. Ho cercato la risposta per un'ora e finalmente l'ho trovata qui. – applecrusher

1

C'è la sezione sulla sicurezza nella documentazione Flask-Admin: http://flask-admin.readthedocs.io/en/latest/introduction/#authorization-permissions

+0

L'ho già esaminato prima di postare qui e in questa sezione gli esempi mostrano come usare 'flask-admin' e non' flask-security'. Sto specificatamente cercando di farlo tramite 'flask-security' poiché fornisce più funzionalità di' flask-login'. Qualsiasi aiuto sarebbe apprezzato. –

+0

@Joes https://stackoverflow.com/questions/46914054/access-control-for-flask-admin – Sparrowcide

6

Poiché questo è il primo risultato per la ricerca google "sicurezza sicura per la sicurezza dei flask", e non esiste ancora una soluzione pronta per l'uso, penso di poter contribuire.

Una domanda simile è stata posta sul progetto di flask-admin Issue List e un semplice esempio utilizzando flask-login e mogodb è fornito here.

Ho fatto un esempio utilizzando SQLAchemy per un database sqlite e la sicurezza del pallone. Vedere l'applicazione pallone esempio riportato di seguito:

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

Si prega di fare riferimento alla documentazione pallone-sicurezza per imparare how to customize the login page.

Spero che questo aiuti.

0

Io uso la risposta di @RamiMac per tutte le viste secondarie, ma per l'indice uno (per impostazione predefinita /admin), utilizzo questo metodo, re-avvolgere il metodo con un ruolo admin richiesto per la visualizzazione.

@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() 

Nel mio progetto, questo va direttamente dopo tutto il mio codice Flask-Admin, che di per sé è nel suo script di avvio, custom_flaskadmin.py.