2016-03-25 15 views
5

Ho preso l'esempio di autenticazione Flask-Admin da here e l'ho modificato leggermente.Flask-Admin - Accesso basato sui ruoli - Modifica dell'accesso in base al ruolo

Ho aggiunto il seguente blocco alla vista sottostante, ma non mostra il pulsante di esportazione. Mi aspettavo che aggiungesse l'opzione di esportazione alle viste di amministrazione. Stampa ---superuser sulla console.

 if current_user.has_role('superuser'): 
      can_export = True 
      print ' ---- superuser ' 

Ho usato la funzionalità di esportazione molte volte in precedenza. Funzionerà se inserisco la dichiarazione can_export = True appena sotto class MyModelView(sqla.ModelView): Sto usando questo come esempio di controllo dell'accesso alla creazione/modifica/etc in base al ruolo dell'utente. Ad esempio, desidero avere un ruolo di sola lettura in cui can_create = False, can_edit = False, ecc.

Qualcuno può aiutare? Qualcuno può dirmi cosa sto facendo di sbagliato?

==

Questa è l'intera vista.

# Create customized model view class 
class MyModelView(sqla.ModelView): 

    def is_accessible(self): 
     if not current_user.is_active or not current_user.is_authenticated: 
      return False 

     if current_user.has_role('superuser'): 
      return True 

     return False 

    def _handle_view(self, name, **kwargs): 
     """ 
     Override builtin _handle_view in order to redirect users when a view is not accessible. 
     """ 
     if current_user.has_role('superuser'): 
      can_export = True 
      print ' ---- superuser ' 

     if not self.is_accessible(): 
      if current_user.is_authenticated: 
       # permission denied 
       abort(403) 
      else: 
       # login 
       return redirect(url_for('security.login', next=request.url)) 

==

Per riferimento: ho messo il tutto il codice here.

+0

Quale pulsante di esportazione? Flask-Admin non ha funzionalità di esportazione. – dirn

+0

http://flask-admin.readthedocs.org/en/latest/introduction/ dice che lo fa. Quella pagina dice: Per abilitare l'esportazione csv della vista modello: 'can_export = True'. Posso mostrare il pulsante se inserisco 'can_export = True' proprio sotto' class MyModelView (sqla.ModelView): ' –

+1

Cool. Oggi ho imparato qualcosa di nuovo. Basato su quella pagina, 'can_export' è un attributo di classe. La tua è localmente portata al metodo '_handle_view'. Dovresti usare 'self.can_export', anche se dovresti averlo potrebbe essere troppo tardi per impostarlo. – dirn

risposta

0

Per il commento di @ dirn sopra, aggiungendo il self. risolto.

 self.can_export = True 

Grazie @dirn

5

Per espandere ulteriormente, ho continuato con l'esempio di autenticazione come base dall'alto e aggiunto qualche semplice controllo di accesso basato ruolo. Spero che questo possa aiutare qualcuno.

Il codice completo è here. Se vedi qualcosa qui che non è un buon allenamento RBAC, mi piacerebbe saperlo.

Il file app.py principale è:

import os 
from flask import Flask, url_for, redirect, render_template, request, abort 
from flask_sqlalchemy import SQLAlchemy 
from flask_security import Security, SQLAlchemyUserDatastore, \ 
    UserMixin, RoleMixin, login_required, current_user 
from flask_security.utils import encrypt_password 
import flask_admin 
from flask_admin.contrib import sqla 
from flask_admin import helpers as admin_helpers 

# Create Flask application 
app = Flask(__name__) 
app.config.from_pyfile('config.py') 
db = SQLAlchemy(app) 

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
# Define models directly without reflection... 
class Customer(db.Model): 
    CustomerId = db.Column(db.Integer(), primary_key=True) 
    FirstName = db.Column(db.Unicode(40), nullable=False) 
    LastName = db.Column(db.String(20), nullable=False) 
    City = db.Column(db.Unicode(40)) 
    Email = db.Column(db.Unicode(60), unique = True) 

    def __str__(self): 
     return self.CustomerID 

class City(db.Model): 
    Id = db.Column(db.Integer(), primary_key=True) 
    City = db.Column(db.Unicode(40), unique = True) 

    def __str__(self): 
     return self.ID 

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

# Define 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)) 

    def __str__(self): 
     return self.name 

class User(db.Model, UserMixin): 
    id = db.Column(db.Integer, primary_key=True) 
    first_name = db.Column(db.String(255)) 
    last_name = db.Column(db.String(255)) 
    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')) 

    def __str__(self): 
     return self.email 

# Setup Flask-Security 
user_datastore = SQLAlchemyUserDatastore(db, User, Role) 
security = Security(app, user_datastore) 

# Flask views 
@app.route('/') 
def index(): 
    return render_template('index.html') 


# Create customized model view class 
class dgBaseView(sqla.ModelView): 

    column_display_pk = True 
    page_size = 20 
    can_view_details = True 
    #can_export = False 
    can_export = True 

    def _handle_view(self, name, **kwargs): 
     """ 
     Override builtin _handle_view in order to redirect users when a view is not accessible. 
     """ 
     if not self.is_accessible(): 
      if current_user.is_authenticated: 
       # permission denied 
       abort(403) 
      else: 
       # login 
       return redirect(url_for('security.login', next=request.url)) 

class regularRbacView(dgBaseView): 

    def is_accessible(self): 

     # set accessibility... 
     if not current_user.is_active or not current_user.is_authenticated: 
      return False 

     # roles not tied to ascending permissions... 
     if not current_user.has_role('export'): 
      self.can_export = False 

     # roles with ascending permissions... 
     if current_user.has_role('adminrole'): 
      self.can_create = True 
      self.can_edit = True 
      self.can_delete = True 
      self.can_export = True 
      return True 
     if current_user.has_role('supervisor'): 
      self.can_create = True 
      self.can_edit = True 
      self.can_delete = False 
      return True 
     if current_user.has_role('user'): 
      self.can_create = True 
      self.can_edit = True 
      self.can_delete = False 
      return True 
     if current_user.has_role('create'): 
      self.can_create = True 
      self.can_edit = False 
      self.can_delete = False 
      return True 
     if current_user.has_role('read'): 
      self.can_create = False 
      self.can_edit = False 
      self.can_delete = False 
      return True 
     return False 

class lookupRbacView(dgBaseView): 

    def is_accessible(self): 
     # set accessibility... 
     if not current_user.is_active or not current_user.is_authenticated: 
      return False 

     # roles not tied to ascending permissions... 
     if not current_user.has_role('export'): 
      self.can_export = False 

     # roles with ascending permissions... 
     if current_user.has_role('adminrole'): 
      self.can_create = True 
      self.can_edit = True 
      self.can_delete = True 
      self.can_export = True 
      return True 
     if current_user.has_role('supervisor'): 
      self.can_create = True 
      self.can_edit = True 
      self.can_delete = False 
      return True 
     if current_user.has_role('user'): 
      self.can_create = False 
      self.can_edit = False 
      self.can_delete = False 
      return True 
     if current_user.has_role('create'): 
      self.can_create = False 
      self.can_edit = False 
      self.can_delete = False 
      return True 
     if current_user.has_role('read'): 
      self.can_create = False 
      self.can_edit = False 
      self.can_delete = False 
      return True 
     return False 

class SuperView(dgBaseView): 

    can_export = True 

    def is_accessible(self): 
     if not current_user.is_active or not current_user.is_authenticated: 
      return False 
     if current_user.has_role('adminrole'): 
      self.can_create = True 
      self.can_edit = True 
      self.can_delete = True 
      #self.can_export = True 
      return True 
     return False 


# define a context processor for merging flask-admin's template context into the 
# flask-security views. 
@security.context_processor 
def security_context_processor(): 
    return dict(
     admin_base_template=admin.base_template, 
     admin_view=admin.index_view, 
     h=admin_helpers, 
    ) 

# Create admin 
admin = flask_admin.Admin(
    app, 'Rbac RoleBasedAccess', base_template='my_master.html', template_mode='bootstrap3', 
) 

class customer_view(regularRbacView): 

    column_searchable_list = ['CustomerId', 'City', 'Email', 'FirstName', 'LastName',] 
    # make sure the type of your filter matches your hybrid_property 
    column_filters = ['FirstName', 'LastName', 'City', 'Email' ] 
    # column_default_sort = ('part_timestamp', True) 
    #column_export_list = ['CustomerId', 'City', 'Email', 'FirstName', 'LastName',] 

# Add model views 
admin.add_view(SuperView(Role, db.session)) 
admin.add_view(SuperView(User, db.session)) 
admin.add_view(customer_view(Customer, db.session)) 
admin.add_view(lookupRbacView(City, db.session)) 


def build_sample_db(): 
    """ 
    Populate a small db with some example entries. 
    """ 
    import string 

    #db.drop_all() 
    db.create_all() 

    with app.app_context(): 
     read_role = Role(name='read') 
     user_role = Role(name='user') 
     super_user_role = Role(name='adminrole') 
     db.session.add(user_role) 
     db.session.add(super_user_role) 
     db.session.add(Role(name='read')) 
     db.session.add(Role(name='create'))  
     db.session.add(Role(name='supervisor')) 
     db.session.add(Role(name='delete')) 
     db.session.add(Role(name='export')) 
     db.session.commit() 

     test_user = user_datastore.create_user(
      first_name='Admin', 
      email='admin', 
      password=encrypt_password('admin'), 
      roles=[user_role, super_user_role] 
     ) 


     first_names = [ 
      'read', 'create', 'user', 'suser', 'delete', 'Charlie', 'Sophie', 'Mia', 
     ] 
     last_names = [ 
      'Brown', 'Smith', 'Patel', 'Jones', 'Williams', 'Johnson', 'Taylor', 'Thomas', 
     ] 
     roles1 = [ 
      'read', 'create', 'user', 'supervisor', 'delete', 'read', 'read', 'read', 
     ] 

     for i in range(len(first_names)): 
      tmp_email = first_names[i].lower() 
      # initialize the users with simple password... 'a' 
      tmp_pass = 'a' 
      user_datastore.create_user(
       first_name=first_names[i], 
       last_name=last_names[i], 
       email=tmp_email, 
       password=encrypt_password(tmp_pass), 
       roles=[read_role, ] 
      ) 
     db.session.commit() 
    return 

if __name__ == '__main__': 

    # Build a sample db on the fly, if one does not exist yet. 
    app_dir = os.path.realpath(os.path.dirname(__file__)) 
    database_path = os.path.join(app_dir, app.config['DATABASE_FILE']) 
    if not os.path.exists(database_path): 
     build_sample_db() 
    app.run(host='0.0.0.0', port=5000, debug=True) 

Il config.py è:

# http://stackoverflow.com/questions/5055042/whats-the-best-practice-using-a-settings-file-in-python 
import creds 

# Create dummy secret key so we can use sessions 
SECRET_KEY = creds.cred['secretkey'] 

# Create in-memory database 
DATABASE_FILE = 'fground.sqlite' 
SQLALCHEMY_DATABASE_URI = creds.cred['dbspec'] + DATABASE_FILE 
SQLALCHEMY_ECHO = True 

# Flask-Security config 
SECURITY_URL_PREFIX = "/admin" 
SECURITY_PASSWORD_HASH = "pbkdf2_sha512" 
SECURITY_PASSWORD_SALT = creds.cred['csalt'] 

# Flask-Security URLs, overridden because they don't put a/at the end 
SECURITY_LOGIN_URL = "/login/" 
SECURITY_LOGOUT_URL = "/logout/" 
SECURITY_REGISTER_URL = "/register/" 

SECURITY_POST_LOGIN_VIEW = "/admin/" 
SECURITY_POST_LOGOUT_VIEW = "/admin/" 
SECURITY_POST_REGISTER_VIEW = "/admin/" 

# Flask-Security features 
SECURITY_REGISTERABLE = True 
SECURITY_SEND_REGISTER_EMAIL = False 

Il creds.py è:

cred = dict(
    secretkey = '123232323238', 
    dbspec = 'sqlite:///', 
    csalt  = "ATGUOHAELKiubaq3fgo8hiughaerGOJAEGj", 
    dbu = 'user', 
    dbp = 'pass', 
) 

Per eseguire questo, consiglio di iniziare con l'esempio di auth-admin admin sopra e poi copiare questi file in quell'esempio. L'esecuzione dovrebbe creare un database con utenti e ruoli. Inoltre, è possibile ottenere tutto il codice pronto per il github link.

Problemi correlati