Flask-RBAC

Flask-RBAC provides a Role-based Access Control module in Flask applications. It can help you to control different role of users to access your website.

Installation

Your can use pip to install Flask-RBAC:

$ pip install flask-rbac

Quick Start

This documents show how to create Flask-RBAC extension easily and quickly.

Configuration Your Application

As same as many Flask extensions, you need to configuration your application:

from flask import Flask
from flask_rbac import RBAC

app = Flask(__name__)
rbac = RBAC(app)

or you can configuration using factory method:

from flask import Flask
from flask_rbac import RBAC

rbac = RBAC()

def create_app():
    app = Flask(__name__)

    rbac.init_app(app)

    return app

Mode Setting

There are two modes for Flask-RBAC, RBAC_USE_WHITE decide whether use white list to check the permission. And it set False to default.

RBAC_USE_WHITE = True Only allowing rules can access the resources. This means, all deny rules and rules you did not add cannot access the resources.
RBAC_USE_WHITE = False Only denying rules cannot access the resources. In case you set an allow rule, denying rules will also be automatically created for existing non-added roles in this route.

Change it using:

app.config['RBAC_USE_WHITE'] = True

Set Role Model

Flask-RBAC implements some methods need by Flask-RBAC in RoleMixin class. You can use RoleMixin as your role model:

class Role(RoleMixin):
    pass

anonymous = Role('anonymous')

However, if your application is working under SQLAlchemy, and you want to save the roles in database, you need to override the Role class to adapt your application, here is an example:

from flask_rbac import RoleMixin
from your_package.app import db

roles_parents = db.Table(
    'roles_parents',
    db.Column('role_id', db.Integer, db.ForeignKey('role.id')),
    db.Column('parent_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(20))
    parents = db.relationship(
        'Role',
        secondary=roles_parents,
        primaryjoin=(id == roles_parents.c.role_id),
        secondaryjoin=(id == roles_parents.c.parent_id),
        backref=db.backref('children', lazy='dynamic')
    )

    def __init__(self, name):
        RoleMixin.__init__(self)
        self.name = name

    def add_parent(self, parent):
        # You don't need to add this role to parent's children set,
        # relationship between roles would do this work automatically
        self.parents.append(parent)

    def add_parents(self, *parents):
        for parent in parents:
            self.add_parent(parent)

    @staticmethod
    def get_by_name(name):
        return Role.query.filter_by(name=name).first()

After create role model, you can add your model to Flask-RBAC:

rbac.set_role_model(Role)

Or use decorator to set role model for Flask-RBAC:

@rbac.as_role_model
class Role(RoleMixin):
    # codes go here

Set User Model

Same as the RoleMixin, UserMixin implements some methods for Flask-RBAC, You can extend it directly:

from flask_rbac import UserMixin

class User(UserMixin):
    pass

a_user = User()

Well, if your application works under SQLAlchemy:

from flask_rbac import UserMixin
from your_package.app import db

users_roles = db.Table(
    'users_roles',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
    db.Column('role_id', db.Integer, db.ForeignKey('role.id'))
)

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(30), unllable=True)
    # Other columns
    roles = db.relationship(
        'Role',
        secondary=users_roles,
        backref=db.backref('roles', lazy='dynamic')
    )

    def add_role(self, role):
        self.roles.append(role)

    def add_roles(self, roles):
        for role in roles:
            self.add_role(role)

    def get_roles(self):
        for role in self.roles:
            yield role

Same as role model, you should add user model to Flask-RBAC:

rbac.set_user_model(User)

Or using decorator:

@rbac.as_user_model
class User(UserMixin):
    # codes go here

Set User Loader

Flask-RBAC need to know who is current user, so it requires you to provide a function which tells it who is current user.

Flask-RBAC will load current user from Flask-Login if you have install it by default.

If you save current user in flask.g, here is an example for you:

from flask import g, current_app

@app.route('/signin', methods=['POST'])
@rbac.allow(['anonmous'], methods=['POST'])
def signin():
    # Sign in logic...
    g.current_user = user

def get_current_user():
    with current_app.request_context():
        return g.current_user

rbac.set_user_loader(get_current_user)

Set Access Rules

You can use allow and deny to add rules to Flask-RBAC:

@app.route('/')
@rbac.allow(['anonymous'], methods=['GET'])
def index():
    # your codes.
    pass

@app.route('/account/signin', methods=['GET', 'POST'])
@rbac.deny(['logged_user'], methods=['GET', 'POST'])
def signin():
    # show sign in page or handle sign in request.
    pass

The code above adding two rules:

  • Allows user of anonymous role to GET /.
  • Deny user of logged_user role to GET and POST /account/signin.

Flask itself assumes the name of the view function as the endpoint for the registered URL rule, that’s why in rules validation by default we use the decorated function name to check against the endpoint of the input request. But, in case you specified a different endpoint or you use the decorators inside a blueprint or abstracted blueprints extensions like Flask-Admin you can directly specify to the decorator the endpoint used in your route.

@app.route('/signin', methods=['GET', 'POST'], endpoint='account.signin')
@rbac.deny(['logged_user'], methods=['GET', 'POST'],
    endpoint='account.signin')
def signin():
    # show sign in page or handle sign in request.
    pass

API Reference

Flask.ext.rbac.RBAC

class flask_rbac.__init__.RBAC(app=None, **kwargs)

This class implements role-based access control module in Flask. There are two way to initialize Flask-RBAC:

app = Flask(__name__)
rbac = RBAC(app)

or:

rbac = RBAC
def create_app():
    app = Flask(__name__)
    rbac.init_app(app)
    return app
Parameters:
  • app – the Flask object
  • role_model – custom role model
  • user_model – custom user model
  • user_loader – custom user loader, used to load current user
  • permission_failed_hook – called when permission denied.
allow(roles, methods, with_children=True, endpoint=None)

This is a decorator function.

You can allow roles to access the view func with it.

An example:

@app.route('/website/setting', methods=['GET', 'POST'])
@rbac.allow(['administrator', 'super_user'], ['GET', 'POST'])
def website_setting():
    return Response('Setting page.')
Parameters:
  • roles – List, each name of roles. Please note that, anonymous is refered to anonymous. If you add anonymous to the rule, everyone can access the resource, unless you deny other roles.
  • methods – List, each name of methods. methods is valid in [‘GET’, ‘POST’, ‘PUT’, ‘DELETE’]
  • with_children – Whether allow children of roles as well. True by default.
as_role_model(model_cls)

A decorator to set custom model or role.

Parameters:model_cls – Model of role.
as_user_model(model_cls)

A decorator to set custom model or user.

Parameters:model_cls – Model of user.
deny(roles, methods, with_children=False, endpoint=None)

This is a decorator function.

You can deny roles to access the view func with it.

An example:

@app.route('/article/post', methods=['GET', 'POST'])
@rbac.deny(['anonymous', 'unactivated_role'], ['GET', 'POST'])
def article_post():
    return Response('post page.')
Parameters:
  • roles – List, each name of roles.
  • methods – List, each name of methods. methods is valid in [‘GET’, ‘POST’, ‘PUT’, ‘DELETE’]
  • with_children – Whether allow children of roles as well. True by default.
exempt(view_func)

Exempt a view function from being checked permission. It is useful when you are using white list checking.

Example:

@app.route('/everyone/can/access')
@rbac.exempt
def everyone_can_access():
    return 'Hello~'
Parameters:view_func – The view function going to be exempted.
get_app(reference_app=None)

Helper method that implements the logic to look up an application.

has_permission(method, endpoint, user=None)

Return does the current user can access the resource. Example:

@app.route('/some_url', methods=['GET', 'POST'])
@rbac.allow(['anonymous'], ['GET'])
def a_view_func():
    return Response('Blah Blah...')

If you are not logged.

rbac.has_permission(‘GET’, ‘a_view_func’) return True. rbac.has_permission(‘POST’, ‘a_view_func’) return False.

Parameters:
  • method – The method wait to check.
  • endpoint – The application endpoint.
  • user – user who you need to check. Current user by default.
init_app(app)

Initialize application in Flask-RBAC. Adds (RBAC, app) to flask extensions. Adds hook to authenticate permission before request.

Parameters:app – Flask object
set_hook(hook)

Set hook which called when permission is denied If you haven’t set any hook, Flask-RBAC will call:

abort(403)
Parameters:hook – Hook function
set_role_model(model)

Set custom model of role.

Parameters:model – Model of role.
set_user_loader(loader)

Set user loader, which is used to load current user. An example:

from flask_login import current_user
rbac.set_user_loader(lambda: current_user)
Parameters:loader – Current user function.
set_user_model(model)

Set custom model of User

Parameters:model – Model of user

Flask.ext.rbac.model.RoleMixin

class flask_rbac.model.RoleMixin(name=None)

This provides implementations for the methods that Flask-RBAC wants the role model to have.

Parameters:name – The name of role.
add_parent(parent)

Add a parent to this role, and add role itself to the parent’s children set. you should override this function if neccessary.

Example:

logged_user = RoleMixin('logged_user')
student = RoleMixin('student')
student.add_parent(logged_user)
Parameters:parent – Parent role to add in.
add_parents(*parents)

Add parents to this role. Also should override if neccessary. Example:

editor_of_articles = RoleMixin('editor_of_articles')
editor_of_photonews = RoleMixin('editor_of_photonews')
editor_of_all = RoleMixin('editor_of_all')
editor_of_all.add_parents(editor_of_articles, editor_of_photonews)
Parameters:parents – Parents to add.
classmethod get_all()

Return all existing roles

static get_by_name(name)

A static method to return the role which has the input name.

Parameters:name – The name of role.
get_name()

Return the name of this role

Flask.ext.rbac.model.UserMixin

class flask_rbac.model.UserMixin(roles=[])

This provides implementations for the methods that Flask-RBAC wants the user model to have.

Parameters:roles – The roles of this user should have.
add_role(role)

Add a role to this user.

Parameters:role – Role to add.
add_roles(*roles)

Add roles to this user.

Parameters:roles – Roles to add.

Author & Contributor

  • Yaoda Liu <shonenada@gmail.com>
  • tonyseek
  • lixxu
  • aurigadl
  • trendsetter37
  • hieuvo
  • carlosgalvez-tiendeo