While Flask-Principal is the most popular plugin, it is unnecessary complicated and it just doesn't work in the most cases I need it. I have been trying to force it to work the way I like it, but I have never succeeded. Luckily, I have found an extremely straightforward and lightweight module - permission:
Usage
First you need to define your own rules by subclassing Rule
then
override check()
and deny()
:
# rules.py
from flask import session, flash, redirect, url_for
from permission import Rule
class UserRule(Rule):
def check(self):
"""Check if there is a user signed in."""
return 'user_id' in session
def deny(self):
"""When no user signed in, redirect to signin page."""
flash('Sign in first.')
return redirect(url_for('signin'))
Then you define permissions by subclassing Permission
and override rule()
:
# permissions.py
from permission import Permission
from .rules import UserRule
class UserPermission(Permission):
"""Only signin user has this permission."""
def rule(self):
return UserRule()
There are 4 ways to use the UserPermission
defined above:
1. Use as view decorator
from .permissions import UserPermission
@app.route('/settings')
@UserPermission()
def settings():
"""User settings page, only accessable for sign-in user."""
return render_template('settings.html')
2. Use in view codes
from .permissions import UserPermission
@app.route('/settions')
def settings():
permission = UserPermission()
if not permission.check()
return permission.deny()
return render_template('settings.html')
3. Use in view codes (using with
statement)
from .permissions import UserPermission
@app.route('/settions')
def settings():
with UserPermission():
return render_template('settings.html')
4. Use in Jinja2 templates
First you need to inject your defined permissions to template context:
from . import permissions
@app.context_processor
def inject_vars():
return dict(
permissions=permissions
)
then in templates:
{% if permissions.UserPermission().check() %}
<a href="{{ url_for('new') }}">New</a>
{% endif %}