简单灵活的 Flask 应用权限控制。
项目描述
简单灵活的 Flask 应用权限控制。
特征
简单:您需要做的就是继承Rule和 Permission类。
灵活:支持规则继承和按位运算(& 和|)来构建您自己的规则。
安装
$ pip install permission
规则
Rule有 3 个可以被覆盖的方法:
base():定义基本规则。
check():确定是否应该通过此规则。
deny():将在check()失败时执行。
您应该始终覆盖check()和deny(),同时根据需要覆盖 base()。
允许
权限有 1 种可以被覆盖的方法:
rule():定义此权限所需的规则
您应该始终覆盖rule()。
Permission有 2 个可以在代码中使用的实例方法:
check():调用这个来检查这个权限的规则
deny():当check()失败时调用它来执行代码
用法
首先,您需要通过继承Rule来定义自己的规则,然后覆盖check()和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'))
然后通过继承Permission和覆盖 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()
使用上面定义的UserPermission有 4 种方法:
1.用作视图装饰器
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.在视图代码中使用
from .permissions import UserPermission
@app.route('/settions')
def settings():
permission = UserPermission()
if not permission.check()
return permission.deny()
return render_template('settings.html')
3.在视图代码中使用(使用``with``语句)
from .permissions import UserPermission
@app.route('/settions')
def settings():
with UserPermission():
return render_template('settings.html')
注意:如果您在权限检查失败时不引发异常(换句话说,将调用 规则的拒绝() ),则会引发PermissionDeniedException以停止执行 with-body 代码。顺便说一句,您可以根据需要导入此异常:
from permission import PermissionDeniedException
4.在Jinja2模板中使用
首先,您需要将定义的权限注入模板上下文:
from . import permissions
@app.context_processor
def inject_vars():
return dict(
permissions=permissions
)
然后在模板中:
{% if permissions.UserPermission().check() %}
<a href=<s>"{{ url_for('new') }}"</s>>New</a>
{% endif %}
规则继承
需要说明的是,这里的继承与 Python 类的继承不是一回事,它只是意味着你可以使用 RuleA 作为 RuleB 的基本规则。
我们通过重写base()来实现这一点。
假设管理员用户应该始终是用户:
# rules.py
from flask import session, abort, flash, redirect, url_for
from permission import Rule
class UserRule(Rule):
def check(self):
return 'user_id' in session
def deny(self):
flash('Sign in first.')
return redirect(url_for('signin'))
class AdminRule(Rule):
def base(self):
return UserRule()
def check(self):
user_id = int(session['user_id'])
user = User.query.filter(User.id == user_id).first()
return user and user.is_admin
def deny(self):
abort(403)
规则位运算
RuleA & RuleB表示当 RuleA 和 RuleB 都通过时才会通过。
规则A | RuleB表示将通过 RuleA 或 RuleB。
假设我们需要用 Flask 建立一个论坛。只有主题创建者和管理员用户可以编辑主题:
首先定义规则:
# rules.py
from flask import session, abort, flash, redirect, url_for
from permission import Rule
from .models import User, Topic
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'))
class AdminRule(Rule):
def base(self):
return UserRule()
def check(self):
user_id = int(session['user_id'])
user = User.query.filter(User.id == user_id).first()
return user and user.is_admin
def deny(self):
abort(403)
class TopicCreatorRule(Rule):
def __init__(self, topic):
self.topic = topic
super(TopicCreatorRule, self).__init__()
def base(self):
return UserRule()
def check(self):
return topic.user_id == session['user_id']
def deny(self):
abort(403)
然后定义权限:
# permissions.py
from permission import Permission
class TopicAdminPermission(Permission):
def __init__(self, topic):
self.topic = topic
super(TopicAdminPermission, self).__init__()
def rule(self):
return AdminRule() | TopicCreatorRule(self.topic)
所以我们可以在edit_topic视图中使用TopicAdminPermission:
from .permissions import TopicAdminPermission
@app.route('topic/<int:topic_id>/edit')
def edit_topic(topic_id):
topic = Topic.query.get_or_404(topic_id)
permission = TopicAdminPermission(topic)
if not permission.check():
return permission.deny()
...
执照
麻省理工学院