Skip to content Skip to sidebar Skip to footer

Flask-admin Is_accessible Usage

I've checked the docs and It's pretty vague how the is_accessible method should be implemented. Here is what the docs of flask admin showed class MicroBlogModelView(sqla.ModelView)

Solution 1:

See the example code below - most of the code is taken verbatim from Quokka CMS

Define a Roled mixin that handles def is_accessible(self) and def _handle_view(self, name, *args, **kwargs).

In the example I've used a function , def is_accessible(roles_accepted=None, user=None), to handle the logic of determining if a role is acceptable.

Define a view class from sqla ModelView and the Roled mixin, namely:

classAdminView(Roled, ModelView):def__init__(self, *args, **kwargs):
        self.roles_accepted = kwargs.pop('roles_accepted', list())
        super(AdminView, self).__init__(*args, **kwargs)

Derive your view models from this class:

classUserView(AdminView):
    form_excluded_columns = ('password')   

classRoleView(AdminView):
    passclassPostView(AdminView):
    pass

Add your views to the admin class in the normal manner but pass a list of allowed role names via the roles_accepted keyword:

admin.add_view(UserView(model=User, session=db.session, category='Account', name='Users', roles_accepted=['admin']))
admin.add_view(RoleView(model=Role, session=db.session, category='Account', name='Roles', roles_accepted=['admin']))
admin.add_view(PostView(model=Post, session=db.session, category='Blog', name='Posts (Editor Only)', roles_accepted=['editor']))
admin.add_view(PostView(model=Post, session=db.session, category='Blog', name='Posts (Admins & Editors)', endpoint="post_special", roles_accepted=['editor', 'admin']))

See full single file code below. This was tested under Python 2.7.9, Flask 0.10.1, flask-admin 1.1.0, flask-security 1.7.4 and flask-login 0.2.11

from datetime import datetime
from flask import Flask, redirect, current_app
from flask.ext.admin import Admin
from flask.ext.admin.contrib.sqla import ModelView
from flask.ext.admin.menu import MenuLink
from flask.ext.security import (
    current_user,
    url_for_security,
    UserMixin,
    RoleMixin,
    SQLAlchemyUserDatastore,
    Security
)
from flask.ext.security.utils import encrypt_password
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'super-secret'
app.config['SECURITY_PASSWORD_HASH'] = 'pbkdf2_sha512'
app.config['SECURITY_PASSWORD_SALT'] = '16a0af319890f662055ba10aecff37e7e033db3fba737e55'
app.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = 'email'

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)


classRole(db.Model, RoleMixin):
    __tablename__ = 'roles'id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Unicode(length=64), unique=True)
    description = db.Column(db.Unicode(length=255), nullable=True)

    def__unicode__(self):
        returnu"{name} ({role})".format(name=self.name, role=self.description or'Role')

user_to_role = db.Table('user_to_role',
    db.Column('user_id', db.Integer(), db.ForeignKey('users.id')),
    db.Column('role_id', db.Integer(), db.ForeignKey('roles.id')))


classUser(db.Model, UserMixin):
    __tablename__ = 'users'id = db.Column(db.Integer, primary_key=True)

    first_name = db.Column(db.Unicode(length=255), nullable=False)
    last_name = db.Column(db.Unicode(length=255), nullable=False)

    email = db.Column(db.Unicode(length=254), unique=True, nullable=True)
    password = db.Column(db.Unicode(length=255), nullable=False)
    active = db.Column(db.Boolean(), default=False)

    roles = db.relationship('Role', secondary=user_to_role, backref=db.backref('users', lazy='select'))

    def__unicode__(self):
        returnu"{first_name} ({last_name})".format(first_name=self.first_name, last_name=self.last_name)


classPost(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(255))
    content = db.Column(db.Text, nullable=False)

    def__unicode__(self):
        return self.title


defget_current_user():
    from flask.ext.security import current_user
    try:
        return User.objects.get(id=current_user.id)
    except Exception as e:
        # logger.warning("No user found: %s", str(e))return current_user


defis_accessible(roles_accepted=None, user=None):
    user = user or get_current_user()
    # uncomment if "admin" has access to everything# if user.has_role('admin'):#     return Trueif roles_accepted:
        accessible = any(
            [user.has_role(role) for role in roles_accepted]
        )
        return accessible
    returnTrueclassRoled(object):

    defis_accessible(self):
        roles_accepted = getattr(self, 'roles_accepted', None)
        return is_accessible(roles_accepted=roles_accepted, user=current_user)

    def_handle_view(self, name, *args, **kwargs):
        ifnot current_user.is_authenticated():
            return redirect(url_for_security('login', next="/admin"))
        ifnot self.is_accessible():
            # return self.render("admin/denied.html")return"<p>Access denied</p>"classAdminView(Roled, ModelView):

    def__init__(self, *args, **kwargs):
        self.roles_accepted = kwargs.pop('roles_accepted', list())
        super(AdminView, self).__init__(*args, **kwargs)


classUserView(AdminView):
    form_excluded_columns = ('password')


classRoleView(AdminView):
    passclassPostView(AdminView):
    pass# Setup Flask-Security
security = Security(app, SQLAlchemyUserDatastore(db, User, Role))

@app.route('/')defindex():
    _login = url_for_security('login', next="/admin")
    _logout = url_for_security('logout', next="/admin")
    return'''
        <a href="/admin/">Click me to get to Admin!</a><br>
        <a href="{login}">Click me to get to login!</a><br>
        <a href="{logout}">Click me to get to logout!</a>
        '''.format(login=_login, logout=_logout)


# Create admin
admin = Admin(app, name='Admin')
admin.add_view(UserView(model=User, session=db.session, category='Account', name='Users', roles_accepted=['admin']))
admin.add_view(RoleView(model=Role, session=db.session, category='Account', name='Roles', roles_accepted=['admin']))
admin.add_view(PostView(model=Post, session=db.session, category='Blog', name='Posts (Editor Only)', roles_accepted=['editor']))
admin.add_view(PostView(model=Post, session=db.session, category='Blog', name='Posts (Admins & Editors)', endpoint="post_special", roles_accepted=['editor', 'admin']))
admin.add_link(MenuLink(name='Public Website', category='', url='/'))


defbuild_db():
    users = [
        {
            'first_name': 'Super',
            'last_name': 'User',
            'email': 'admin@example.com',
            'active': True,
            'password' : encrypt_password('password'),
            'roles': ['admin']
        },
        {
            'first_name': u'Post',
            'last_name': u'Editor',
            'email': 'editor@example.com',
            'active': True,
            'password': encrypt_password('password'),
            'roles': ['editor']
        },

    ]

    posts = [
        {
            'title': "de Finibus Bonorum et Malorum - Part I",
            'content': "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut"
        },
        {
            'title': "de Finibus Bonorum et Malorum - Part II",
            'content': "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque"
        },
        {
            'title': "de Finibus Bonorum et Malorum - Part III",
            'content': "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium"
        }
    ]

    db.drop_all()
    db.create_all()

    security = current_app.extensions.get('security')

    security.datastore.create_role(name=u"admin", description=u'Administers the system')
    security.datastore.create_role(name=u"editor", description=u'Can edit posts')

    for user in users:
        roles = user.pop('roles')
        user_db = security.datastore.create_user(**user)
        for role_name in roles:
            role_from_db = security.datastore.find_role(role_name)
            security.datastore.add_role_to_user(user_db, role_from_db)
        security.datastore.activate_user(user_db)
        user_db.confirmed_at = datetime.now()

    security.datastore.commit()

    for row in posts:
        post = Post(**row)
        db.session.add(post)

    db.session.commit()


@app.before_first_requestdefcreate_user():
    build_db()

if __name__ == '__main__':
    app.run(debug=True)

Solution 2:

It's called automatically each time the view is accessed. You can check this by using a print statement. Run your app and look in the console window.

classMicroBlogModelView(sqla.ModelView):defis_accessible(self):
    print "Called ME!!!!!!!!"return login.current_user.is_authenticated()

definaccessible_callback(self, name, **kwargs):
    # redirect to login page if user doesn't have accessreturn redirect(url_for('login', next=request.url))

Post a Comment for "Flask-admin Is_accessible Usage"