Skip to content

Instantly share code, notes, and snippets.

@hustlzp
Last active February 22, 2019 17:42
Show Gist options
  • Save hustlzp/8468273 to your computer and use it in GitHub Desktop.
Save hustlzp/8468273 to your computer and use it in GitHub Desktop.
Simple permission control in Flask.
# coding: utf-8
from flask import request, g
from functools import wraps
from flask import abort, session, redirect, url_for, flash
from .models import Topic, Attachment
from . import roles
def require_visitor(func):
"""仅允许非登陆用户访问,如signin页面"""
@wraps(func)
def decorator(*args, **kwargs):
if g.current_user:
return redirect(url_for('forum.index'))
return func(*args, **kwargs)
return decorator
class Permission(object):
def __init__(self, role, extra=True, super_extra=True):
"""extra用于在同级别user中筛选,super_extra用于允许高级别用户获取此权限"""
self.role = role
self.extra = extra
self.super_extra = super_extra
def __call__(self, func):
@wraps(func)
def decorator(*args, **kwargs):
if not self.check():
return self.deny()
return func(*args, **kwargs)
return decorator
def check(self):
"""判断是否满足权限条件"""
if g.current_role < self.role:
return False
elif g.current_role == self.role:
return self.extra
return self.super_extra
def deny(self, next_url=""):
"""针对不同的role进行不同的处理"""
if g.current_role == roles.VisitorRole:
flash('此操作需要登录账户')
return redirect(url_for('account.signin', next=next_url or request.url))
elif g.current_role == roles.NewUserRole:
flash('请登录邮箱激活账户')
return redirect(url_for('forum.index'))
abort(403)
new_user_permission = Permission(roles.NewUserRole)
user_permission = Permission(roles.UserRole)
admin_permission = Permission(roles.AdminRole)
super_admin_permission = Permission(roles.SuperAdminRole)
class TopicOwnerPermission(Permission):
def __init__(self, topic_id):
can = g.current_user and Topic.query.filter(Topic.id == topic_id).filter(
Topic.user_id == g.current_user.id).count() > 0
Permission.__init__(self, roles.UserRole, can)
class AttachmentOwnerPermission(Permission):
def __init__(self, attachment_id):
can = g.current_user and Attachment.query.filter(Attachment.id == attachment_id).filter(
Attachment.user_id == g.current_user.id).count() > 0
Permission.__init__(self, roles.UserRole, can)
# coding: utf-8
SuperAdminRole = 5
AdminRole = 4
UserRole = 3
NewUserRole = 2
BanUserRole = 1
VisitorRole = 0
# 装饰action
@bp.route('/reply/<int:reply_id>/ban')
@admin_permission
def ban_reply(reply_id):
"""Proc: ban reply"""
reply = Reply.query.get_or_404(reply_id)
reply.ban = True
reply.baned = datetime.datetime.now()
db.session.add(reply)
db.session.commit()
flash('已将此回复移入回收站')
return redirect(url_for('.topic', topic_id=reply.topic_id))
# 在action中使用
@bp.route('/attachment/delete', methods=['POST'])
def delete_attachment():
attachment_id = request.form.get('attachment_id')
permission = AttachmentOwnerPermission(attachment_id)
if not permission.check():
return permission.deny()
attachment = Attachment.query.get_or_404(attachment_id)
db.session.delete(attachment)
db.session.commit()
return json.dumps({'result': 'ok'})
# 用于jinja模板
@app.context_processor
def inject_vars():
from . import roles, permissions
return dict(
roles=roles,
permissions=permissions
)
"""
{% if permissions.TopicOwnerPermission(topic.id).check() %}
<div class="btn-group btn-group-xs">
<a class="btn btn-default btn-ban-topic"
href="{{ url_for('forum.ban_topic', topic_id=topic.id) }}" title="移入回收站">
<i class="fa fa-trash-o"></i>
</a>
<a class="btn btn-default"
href="{{ url_for('forum.edit_topic', topic_id=topic.id) }}" title="编辑">
<i class="fa fa-pencil"></i>
</a>
</div>
{% endif %}
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment