Django基于角色的观点?

时间:2009-10-10 00:29:48

标签: django architecture acl

我正在寻找其他人如何构建这一点的一些意见。我将提供基于类(django组)的视图。

例如,用户的组将确定他或她将访问哪些视图/模板。我正在考虑存储路径以查看表中的函数,以确定用户的链接栏将包含哪些内容。还可以存储过滤器规范以确定将填充这些模板的行。

一个很好的例子是医院护理单位。一个单位的护士无需看到整个医院的病人。他们只需要看病人。同一单位的医生也只需要看到这些患者,但他们应该能够获得更多的功能。

这是通过某些第三方应用程序完成的吗?那你怎么解决这个问题呢?

谢谢, 皮特

9 个答案:

答案 0 :(得分:42)

Django已经拥有了一个群组和权限系统,这可能就足够了。

http://docs.djangoproject.com/en/dev/topics/auth/

通常在您的代码中检查用户是否拥有权限。用户拥有自己的权限以及他所属的组的权限。您可以从管理控制台轻松管理它。

您需要查看两个部分。

  1. 检查用户是否在请求页面 有权这样做。
  2. 如果他,则仅显示指向用户的链接 有权限。
  3. 对于1.您可以检查装饰器中的权限:

    from django.contrib.auth.decorators import permission_required
    
    @permission_required('polls.can_vote')
    def some_view(request):
    

    对于2.当前登录用户的权限存储在模板变量{{perms}}中。此代码检查与上述相同的权限。

    {% if perms.polls.can_vote %}
        <a href="/vote">vote</a>
    {% endif %}
    

    要生成链接列表,您可以迭代user.get_all_permissions()并从字典中获取链接(或生成链接的函数):

    def more_elaborate_list_of_links_for_a_perm(user):
        return ["/link1", ...]
    
    _LINKS = {
        'polls.can_vote' : lambda u: ["/user/specific/link/" + u.id],
        'polls.can_close': lambda u: ['/static/link/1', 'static/link/2'],
        'polls.can_open' : more_elaborate_list_of_links_for_a_perm
    }
    
    def gen_links(user):
        # get_all_permissions also gets permissions for users groups
        perms = user.get_all_permissions()
        return sum((_LINKS[p](user) for p in perms if p in _LINKS), [])
    

    可能还有很多其他方法。

答案 1 :(得分:5)

Django中有一个关于基于角色的权限的新项目非常有趣: http://bitbucket.org/nabucosound/django-rbac

答案 2 :(得分:4)

我们遇到了类似的问题。 Django的团队并不适合这个,但是你可以把它们塞进去。

我们这样做的方式如下:

每个访问控制对象都与groups表具有ManyToMany关系。每组用于定义特定类型的权限(“可以查看患者基础知识”,“可以编辑患者联系信息”等)。用户被添加到他们应该拥有权限的组中(在您看到的只有这家医院的患者的例子中,您可能有一个“谷视图 - 医院”组。)

然后,当您向用户显示记录列表时,将根据两个组的组合进行过滤。用户必须具有查看给定对象的所有关联组权限。

如果您的系统需要它,您可以保留单独的ManyToMany否定权限或单独的读/写权限。您还可以定义一组元组(医生,护士),这些元组会导致查找过滤器检索实际的权限子集。

就链接栏问题而言,您可以使用相同的系统以编程方式生成这些 - 基于用户可以查看或编辑的对象类进行过滤,然后使用get_absolute_url()类型函数(可能称之为get_index_url())以返回每类对象索引的链接。

因为所有这些都相当复杂,你可能最终想要为这些事情做一些级别的缓存,但是在你进行优化之前让它工作。它是可能的,并且它在代码中的含义不如单词。

答案 3 :(得分:2)

不久前我也遇到过类似的问题。我们的解决方案可以解决问题,但对于您的情况来说可能过于简单。像大家一样,我们使用django权限系统来控制用户与模型的交互。但是,我们不仅尝试对用户进行分组,还通过GenericForeignKey对对象进行分组。

我们建立了一个与自身相关联的模型,以便开发层次结构。

class Group( models.Model ):
    name = models.CharField( ... )
    parent = models.ForeignKey( 'self', blank=True, null=True)
    content_type = models.ForeignKey( ContentType )
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey( 'content_type', 'object_id' )
    ...

为了使其工作,我们还创建了一个模型作为django用户模型的用户配置文件。它包含的是一个链接到上面的Group模型的ManyToManyField。这允许我们根据需要授予用户访问零个或多个组的权限。 (documentation

class UserProfile( models.Model ):
    user = models.ForeignKey( User, unique=True )
    groups = models.ManyToManyField( Group )
    ...

这给了我们两全其美,让我们不要试图把所有东西都塞进django的许可系统。我正在使用这个基本设置来控制用户访问体育内容(一些用户可以访问整个联盟,一些只有一两个会议,一些只能访问各个团队),并且在这种情况下运行良好。它可能足以满足您的需求。

答案 4 :(得分:1)

如果您不需要真正的每对象ACL,那么您可以使用Django权限系统。要获取所有可用权限的列表:

from django.contrib.auth.models import Permission
perms = Permission.objects.all()

有一个API for other authentication and authorization sources,因此您无需坚持使用此权限表。

您可以根据此授权模型(RBAC)破解此Django系统以满足您的需求,或者您可以提出类似ACL的解决方案。

答案 5 :(得分:1)

在Pinot Noir葡萄酒专家的网站上,我们根据许多不同的标准创建了每个对象的访问权限。如果入站链接具有与特色酒庄的域名匹配的引用字段,则用户获得“酒厂标记”,其扩展到与该酒厂相关的所有文章,品尝笔记等。我们使用“命名代币”来品尝活动,并且可以访问网站的特定部分。我们甚至使用它来为搜索引擎蜘蛛授予某些类型的权限,然后确保来自这些搜索引擎的链接具有与蜘蛛相同的权限(即没有隐形游戏)。

简短版本是你可以创建一个类(我们称之为TokenBuckets,它们持有令牌),每个对象(在详细页面,或列表页面,或其他任何)可以询问用户的TokenBucket是否具有一定的访问级别是允许的。

基本上它是一种奇怪的ACL系统。创建机制并不难。所有的魔力都在于确定在什么情况下令牌会进入存储桶。

答案 6 :(得分:1)

此问题已在 2009年10月中提出,问题仍然存在于 2012年7月

我搜索了一个好的基于角色的应用,并发现django-permission是最佳结果。

我需要的三个重要功能是角色,查看装饰器模板标签;显然django-permissions拥有所有这些。请阅读docs以了解它的使用情况。

唯一的缺点是它正在开发中。

答案 7 :(得分:1)

您可以使用django用户角色

https://github.com/dabapps/django-user-roles

答案 8 :(得分:0)

我们使用角色基础系统来解决类似的问题。 基本上用户有权担任不同的角色。

查看函数已装饰:

def needs_capability(capability,redirect_to="/cms/"):
   def view_func_wrapper(view_func):
       def wrapped_view_func(request,*args,**kwargs):
           if not request.role._can(capability):
              return HttpResponseRedirect(redirect_to)
           return view_func(request,*args,**kwargs)
       return wrapped_view_func
   return view_func_wrapper

魔法的其余部分位于request.role属性中 设置在上下文处理器中。对于未洗过的群众,经过身份验证的用户获得了一个角色 一个DummyRole。

模板内部进一步限制了对信息的访问:

 {% if not request.role.can.view_all_products %}
          Lots of products, yeah!
 {% endif %}

在我看来,这不是最干净的解决方案,但按预期工作。