Flask-Permissions
Flask-Permissions is a simple Flask permissions extension that works with Flask-SQLAlchemy. It also plays nicely with Flask-Login although that isn't a strict requirement.
Installation
Installs quickly and easily using PIP:
pip install Flask-Permissions
Getting Started
-
Import Flask, Flask-SQLAlchemy, and, if you want, Flask-Login.
from flask import Flask from flask.ext.login import LoginManager, current_user from flask.ext.sqlalchemy import SQLAlchemy
-
Import the
Permissions
object.from flask.ext.permissions.core import Permissions
-
Instantiate the
Permissions
object passing in your Flask app, SQLAlchemy database, and a proxy for the current user.perms = Permissions(app, db, current_user)
-
Sub-class the Flask-Permissions UserMixin. Call the UserMixin's
__init__
in your own__init__
.from app import db from flask.ext.permissions.models import UserMixin class User(UserMixin): # Add whatever fields you need for your user class here. def __init__(self, ...): # Do your user init UserMixin.__init__(self, roles)
-
Add roles to your users and abilities to your roles. This can be done using convenience methods on the
UserMixin
andRole
classes.You'll need a role to start adding abilities.
my_role = Role('admin')
Add abilities by passing string ability names to
role.add_abilities()
. You may pass existing or new abilities in this way. New abilities will be created for you. Add the role to the session and commit when you're done.my_role.add_abilities('create_users', 'delete_users', 'bring_about_world_peace') db.session.add(my_role) db.session.commit()
Add roles on an instance of your
UserMixin
sub-class.my_user = User()
The
user.add_roles()
method works just likerole.add_abilities()
. Pass in a string name or a series of string names. New roles will be created for you. Existing roles will simply be applied to the user. Don't forget to add and commit to the database!my_user.add_roles('admin', 'superadmin') db.session.add(my_user) db.session.commit()
Similarly to the add methods, the classes also offer remove methods that work in the same way. Pass strings to
role.remove_abilities()
oruser.remove_roles()
to remove those attributes from the objects in question. -
Put those decorators to work! Decorate any of your views with the
user_is
oruser_has
decorators fromflask.ext.permissions.decorators
to limit access.from flask.ext.permissions.decorators import user_is, user_has
@user_is
decorator:@app.route('/admin', methods=['GET', 'POST']) @user_is('admin') def admin(): return render_template('admin.html')
@user_has
decorator:@app.route('/delete-users', methods=['GET', 'POST']) @user_has('delete_users') def delete_users(): return render_template('delete-users.html')
Example Implementation
This is ripped almost directly from a project I'm working on that implements Flask-Permissions. Be sure to check out the code comments for help with what does what.
_init_.py
# Import Flask, Flask-SQLAlchemy, and maybe Flask-Login
from flask import Flask
from flask.ext.login import LoginManager, current_user
from flask.ext.sqlalchemy import SQLAlchemy
# Import the Permissions object
from flask.ext.permissions.core import Permissions
# Here, you'll initialize your app with Flask and your database with
# Flask-SQLAlchemy. It might look something like this:
db = SQLAlchemy()
app = Flask(__name__)
app.config.from_object('config')
db.init_app(app)
with app.test_request_context():
db.create_all()
# If you're using Flask-Login, this would be a good time to set that up.
login_manager = LoginManager()
login_manager.init_app(app)
# Now, initialize a Permissions object. I've assigned it to a variable here,
# but you don't have to do so.
perms = Permissions(app, db, current_user)
models.py
# Import your database
from app import db
# I'm using these handy functions for my user's password. Flask is dependent
# on Werkzeug, so you'll have access to these too.
from werkzeug import generate_password_hash, check_password_hash
# Import the mixin
from flask.ext.permissions.models import UserMixin
class User(UserMixin):
# Add whatever fields you need for your user class. Here, I've added
# an email field and a password field
email = db.Column(db.String(120), unique=True)
pwdhash = db.Column(db.String(100))
def __init__(self, email, password, roles=None):
self.email = email.lower()
self.set_password(password)
# Be sure to call the UserMixin's constructor in your class constructor
UserMixin.__init__(self, roles)
def set_password(self, password):
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
def __str__(self):
return self.email
views.py
# Import the decorators
from flask.ext.permissions.decorators import user_is, user_has
# Set up your route and decorate it
@app.route('/admin', methods=['GET', 'POST'])
# Pass the name of the role you want to test for to the decorator
@user_is('admin')
def admin():
return render_template('admin.html')
# Here's an example of user_has
@app.route('/delete-users', methods=['GET', 'POST'])
# Pass the name of the ability you want to test for to the decorator
@user_has('delete_users')
def delete_users():
return render_template('delete-users.html')
License
This extension is available under the MIT license. See the LICENSE file for more details.
Thank You
I hope you enjoy this project. I built Flask-Permissions because I couldn't find a simple permissions system for Flask. This does everything I need, and I feel the implementation is very easy to understand.