34

我正在寻找一些关于其他人如何构建它的输入。我将提供基于类(django 组)的视图。

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

一个很好的例子是医院的护理单位。一个单位的护士不需要看整个医院的病人。他们只需要看他们的病人。同一单位的医生也只需要看这些病人,但他们应该可以使用更强大的功能。

这是通过一些第三方应用程序完成的吗?您将如何解决这个问题?

谢谢,皮特

4

9 回答 9

46

Django 已经有一个组和权限系统,这可能足以满足您的目的。

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

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

您需要查看两个部分。

  1. 检查请求页面的用户是否有权这样做。
  2. 如果他有权限,只显​​示用户的链接。

对于 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), [])

可能还有许多其他方法。

于 2009-10-10T01:00:28.420 回答
5

我们遇到了类似的问题。Django 的组并不真正适合这个,但你可以硬塞进去。

我们这样做的方式如下:

每个受访问控制的对象都与 groups 表具有 ManyToMany 关系。每个组用于定义特定类型的权限(“可以查看患者基本信息”、“可以编辑患者联系信息”等)。用户被添加到他们应该有权访问的组中(在您仅查看该医院的患者的示例中,您可以有一个“valley-view-hospital”组)。

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

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

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

因为这一切都相当复杂,你可能最终想要对这些东西进行某种程度的缓存,但在你优化之前让它工作。这是可能的,而且它的代码比文字更难看。

于 2009-10-29T06:01:03.223 回答
4

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

于 2009-11-02T16:39:19.173 回答
3

不久前我遇到了类似的问题。我们的解决方案成功了,尽管它可能对您的情况来说太简单了。就像大家建议的那样,我们使用 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 User 模型的用户配置文件。它所包含的只是一个链接到上述 Group 模型的 ManyToManyField。这使我们能够根据需要向用户授予对零个或多个组的访问权限。(文档

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

这为我们提供了两全其美的优势,并阻止我们试图将所有内容都塞进 django 的权限系统中。我正在使用这个基本设置来控制用户对体育内容的访问(有些用户可以访问整个联赛,有些只能访问一两个会议,有些只能访问单个球队),并且在这种情况下效果很好。它可能足以满足您的需求。

于 2009-10-30T04:23:28.163 回答
1

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

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

其他身份验证和授权来源有一个API ,因此您无需坚持使用此权限表。

你可以破解这个 Django 系统来满足你在这个授权模型(RBAC)方面的需求,或者你可以想出一个类似 ACL 的解决方案。

于 2009-10-10T02:04:00.867 回答
1

在一个黑比诺葡萄酒专家的网站上,我们根据许多不同的标准创建了每个对象的访问权限。如果入站链接有一个与特色酒厂的域名相匹配的引用字段,那么用户将获得一个“酒厂令牌”,它扩展到与该酒厂相关的所有文章、品酒笔记等。我们在品酒活动中使用“命名代币”进行赠品,他们可以访问网站的特定部分。我们甚至使用它来向搜索引擎蜘蛛授予某些类型的权限,然后确保来自这些搜索引擎的链接具有与蜘蛛相同的权限(即没有伪装游戏)。

简短的版本是您可以创建一个类(我们称它们为持有令牌的 TokenBuckets)并且每个对象(在详细信息页面、列表页面或其他任何地方)都可以询问用户的 TokenBucket 是否允许特定级别的访问。

基本上这是一种奇怪的 ACL 系统。创建机制并不难。所有的魔法都在于确定在什么情况下哪些令牌进入桶中。

于 2009-10-30T04:37:54.373 回答
1

这个问题在2009 年 10 月被问到,到 2012 年7 月问题仍然存在。

我已经搜索了一个好的基于角色的应用程序,并找到django-permission了最好的结果。

我需要的三个重要功能是角色、视图装饰器模板标签;显然django-permissions拥有所有这些。阅读它的文档以了解它的用法。

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

于 2012-07-04T08:22:00.417 回答
1

您可以使用 django 用户角色

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

于 2012-09-07T13:59:13.870 回答
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 %}

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

于 2009-11-02T12:43:57.223 回答