10
votes

Authentication and authorization can be integrated into Flask via the Flask-Login and Flask-Principal plugins. (Or also potentially via the Flask-Security plugin.)

HOWEVER: Flask-Admin--another plugin which provides a backend dashboard--is not a registered blueprint...and, I believe (insomuch as I can tell), the decorators used by Flask-Login and Flask-Principal--and that are otherwise required for a user to access a rendered view...those decorators only operate on views that are part of a registered blueprint.

TWO QUESTIONS:

1) How do I register Flask-Admin as a blueprint in my app, and/or otherwise enable Flask-Login and/or Flask-Principal decorators to protect views associated with Flask-Admin?

2) Why do Flask-Login and Flask-Principal work only on objects which are "natively" part of my app...and not objects (e.g., "Admin" object) that is imported from a plugin? How can I work around this problem...if indeed I am perceiving it correctly?

I gather this is the problem insomuch as it's no sweat for me to create protected views for my app's main index page...or any other page with a view located inside a blueprint. I just can't seem to do it for the Flask-Admin index page (which, again, has no blueprint).

3

3 Answers

11
votes

Flask-Admin provides another way of providing authentication - you simply subclass the AdminIndex and BaseIndex views (or views from contrib if you only need those) and implement the is_accessible method. See the documentation for more details. There is also an example provided in the repository.

4
votes

Simple example how to use Flask-Admin with Flask-Principal

from functools import partial
from flask.ext.admin import Admin as BaseAdmin, AdminIndexView
from flask.ext.principal import Permission, identity_loaded, Need
from flask.ext.security import current_user

PartnerAccessNeed = partial(Need, 'access')

class PartnerAccessPermission(Permission):
    def __init__(self, partner_id):
        need = PartnerAccessNeed(partner_id)
        super(PartnerAccessPermission, self).__init__(need)


@identity_loaded.connect
def on_post_identity_loaded(sender, identity):  
    if hasattr(current_user, 'partner'):
        identity.provides.add(PartnerAccessNeed(current_user.partner.id))

class PartnerAdminIndexView(AdminIndexView):

    def __init__(self, partner_id, *args, **kwargs):
        self.partner_id = partner_id
        super(PartnerAdminIndexView, self).__init__(*args, **kwargs)

    def is_accessible(self):

        if current_user.is_anonymous():
            return redirect(url_for_security('login'))

        if not current_user.is_partner():
            return False

        permission = PartnerAccessPermission(self.partner_id)

        if permission.can():    
            return True

        return False

class PartnerAdmin(BaseAdmin):
    def __init__(self, partner_id, endpoint, name, subdomain, *args, **kwargs):

        index = PartnerAdminIndexView(name=name, 
                                      endpoint=endpoint,
                                      url='/dashboard',
                                      partner_id=partner_id)

        super(PartnerAdmin, self).__init__(base_template='mcnm/master.html', index_view=index, subdomain=subdomain)
0
votes

This repository is a good example of how flask-login and flask-security can be connected with flask-admin.

In this reddit post the author of the boilerplate describes shortly the implementation logic.