我从
here开始使用Flask-Admin auth示例并略微更改了它.
我在下面的视图中添加了以下块,但它没有显示导出按钮.我期待它将导出选项添加到管理视图.它确实打印—超级用户到控制台.
if current_user.has_role('superuser'): can_export = True print ' ---- superuser '
我以前多次使用导出功能.如果我在语句MyModelView(sqla.ModelView)下面放置语句can_export = True,它将起作用:我将此作为基于用户角色控制对创建/编辑/ etc的访问的示例.例如,我想要一个只读的角色,其中can_create = False,can_edit = False等.
有人可以帮忙吗?有人能告诉我我做错了什么吗?
==
这是整个视图.
# 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))
==
解决方法
为了进一步扩展,我继续使用auth示例作为上面的基础,并添加了一些简单的基于角色的访问控制.我希望这可以帮助别人.
完整代码是here.
如果你在这里看到的东西不是一个好的RBAC练习,我想听听它.
主app.py文件是:
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.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,**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','Email' ] # column_default_sort = ('part_timestamp',True) #column_export_list = ['CustomerId',] # 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','supervisor','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)
config.py是:
# https://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
creds.py是:
cred = dict( secretkey = '123232323238',dbspec = 'sqlite:///',csalt = "ATGUOHAELKiubaq3fgo8hiughaerGOJAEGj",dbu = 'user',dbp = 'pass',)
为了运行它,我建议你从上面的flask-admin auth示例开始,然后将这些文件复制到该示例中.运行它应该创建一个包含用户和角色的数据库.此外,您可以准备好在github link上完成所有代码.