Python内置方法实现访问权限控制

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import rbac.acl
import rbac.context

import myapp


#: 建立访问规则注册表和用户标识上下文
acl = rbac.acl.Registry()
identity = rbac.context.IdentityContext(acl)

#: 注册角色
acl.add_role("everyone")
acl.add_role("editor", ["everyone"])
acl.add_role("admin", ["everyone"])

#: 注册资源
acl.add_resource("post")
acl.add_resource("blog-post", ["post"])
acl.add_resource("blog-post:10001", ["blog-post"])


#: 规则断言www.iplaypy.com
def assert_is_author(acl, role, op, res):
    """检查 blog-post 类型的资源是否属于当前用户所有.

    若一个规则的断言返回 False, 权限检查时视为这条规则不存在.
    """
    #: 对资源标识不属于 blog-post 的, 断言无效
    if not isinstance(res, basestring):
        return False
    #: 分割形如 "blog-post:10001" 的资源标识
    splited = res.split(":", 1)
    #: 对资源标识不属于 blog-post 的, 断言无效
    if len(splited) != 2 or splited[0] != "blog-post":
        return False
    #: 取出资源对应的模型
    blog_post = myapp.get_blog_post_by_id(splited[1])
    #: 断言是否生效取决于博文的作者是否是当前用户
    return blog_post.author == myapp.get_current_user()


#: 注册规则
acl.allow("everyone", "view", "post")
acl.allow("editor", "edit", "post", assertion=assert_is_author)
acl.allow("admin", "edit", "post")


#: 角色加载回调函数
@identity.set_roles_loader
def load_roles():
    """加载当前上下文拥有的角色"""
    yield "everyone"
    user = myapp.get_current_user()

    if myapp.user_is_admin(user):
        yield "admin"
    for role in myapp.get_roles(user):
        yield str(role)


#: 使用权限检查(装饰器语法)
@identity.check_permission("view", "blog-post", message="can't view")
def view_blog_post(id):
    blog_post = myapp.get_blog_post_by_id(id)
    if blog_post:
        return blog_post.title
    else:
        return "not found"


#: 使用权限检查(with-context 语法)
def edit_blog_post(id, new_title):
    blog_post = myapp.get_blog_post_by_id(id)
    resource = "blog-post:%s" % id

    with identity.check_permission("edit", resource, message="can't edit"):
        if blog_post:
            blog_post.title = new_title
        else:
            return "not found"


if __name__ == "__main__":
    #: 因为默认拥有 everyone 角色而可行
    print view_blog_post("10001")

    #: 执行下面这句则会抛出 rbac.context.PermissionDenied: can't edit 异常
    # edit_blog_post("10001", "It's a bad day.")

    #: 修改当前用户为 tom
    myapp.current_user = "tom"
    #: 仍然会抛出异常,因为既不是 admin 又不是 author
    #: author 只是普通 editor 角色,但 assert_is_author 调用返回 True
    # edit_blog_post("10001", "It's a bad day.")

    #: 修改当前用户为 tony
    myapp.current_user = "tony"
    #: 因为 editor 角色的授权生效, 可以执行
    edit_blog_post("10001", "It's a bad day.")
    #: 可以看到标题已修改
    print view_blog_post("10001")

    #: 修改当前用户为 admin
    myapp.current_user = "admin"
    print "%s is not author:" % myapp.current_user.capitalize(),
    print myapp.get_blog_post_by_id("10001").author != "admin"
    #: 因为 admin 角色的授权生效, 可以执行
    edit_blog_post("10001", "It's a wonderful day.")
    #: 可以看到标题已修改
    print view_blog_post("10001")

#!/usr/bin/env python
#-*- coding:utf-8 -*-

class BlogPost(object):
    """博文模型"""

    def __init__(self, title, author):
        self.title = title
        self.author = author


current_user = "nobody"
blog_posts = {'10001': BlogPost("It's a sunny day", "tony")}


def get_current_user():
    return current_user


def get_blog_post_by_id(id):
    return blog_posts.get(id)


def user_is_admin(user):
    return user == "admin"


def get_roles(user):
    if user in ("tony", "tom"):
        return ["editor"]
    else:
        return []