2016-03-25 18 views
5

Ich habe das Flask-Admin-Authentifizierungsbeispiel von here genommen und leicht geändert.Flask-Admin Rollenbasierter Zugriff - Zugriff basierend auf der Rolle ändern

Ich habe der folgenden Ansicht den folgenden Block hinzugefügt, aber die Export-Schaltfläche wird nicht angezeigt. Ich habe erwartet, dass die Exportoption den Admin-Ansichten hinzugefügt wird. Es druckt ---superuser auf die Konsole.

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

Ich habe die Export-Funktion viele Male zuvor. Es wird funktionieren, wenn ich die Anweisung can_export = True knapp unter class MyModelView(sqla.ModelView): setze ich benutze dies als ein Beispiel für die Steuerung des Zugriffs auf Erstellen/Bearbeiten/etc basierend auf der Benutzerrolle. Zum Beispiel möchte ich eine schreibgeschützte Rolle haben, wo can_create = False, can_edit = False usw.

Kann jemand helfen? Kann mir jemand sagen, was ich falsch mache?

==

Dies ist die gesamte Ansicht.

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

==

Zum Vergleich: Ich habe den gesamten Code here.

+0

Welcher Exportknopf? Flask-Admin hat keine Exportfunktionalität. – dirn

+0

http://flask-admin.readthedocs.org/en/latest/introduction/ sagt, dass es tut. Auf dieser Seite steht: Um den CSV-Export der Modellansicht zu aktivieren: 'can_export = True'. Ich kann den Button anzeigen lassen, wenn ich 'can_export = True' direkt unter' class MyModelView (sqla.ModelView) setze: ' –

+1

Cool. Heute habe ich etwas Neues gelernt. Basierend auf dieser Seite ist 'can_export' ein Klassenattribut. Ihr Bereich ist lokal auf die '_handle_view'-Methode beschränkt. Sie müssten 'self.can_export' verwenden, obwohl es zu spät ist, das zu setzen. – dirn

Antwort

0

Per @ dirns Kommentar oben, Hinzufügen der self. behoben.

 self.can_export = True 

Dank @dirn

5

weiter auszubauen, ich mit dem Auth Beispiel als Basis fortgesetzt von oben und zusätzlicher Kontrolle einig einfache rollenbasierten Zugriff. Ich hoffe, dass dies jemandem helfen kann.

Der vollständige Code ist here. Wenn Sie hier etwas sehen, das keine gute RBAC-Praxis ist, würde ich gerne etwas darüber erfahren.

Die Haupt app.py Datei ist:

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) 

Die config.py ist:

# 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 

Die creds.py ist:

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

dies ausführen zu können, ich empfehlen, dass Sie mit dem obigen flask-admin auth-Beispiel beginnen und dann diese Dateien in dieses Beispiel kopieren. Beim Ausführen sollte eine Datenbank mit Benutzern und Rollen erstellt werden. Außerdem könntest du den ganzen Code bereit zum Goithub link bekommen.