25

我正在构建一个 Django 站点框架,它将为多个独立站点提供支持,所有站点都使用相同的应用程序,但都有自己的模板。我计划通过使用多个设置文件并为它们设置唯一的 SITE_ID 来实现这一点,就像 Django 文档中为django.contrib.sites 框架所建议的那样

但是,我不希望站点 A 的用户能够登录站点 B。在检查了由 syncdb 创建的用户表之后,我看不到任何可能将用户限制到特定站点的列。我还尝试在一个站点上创建一个用户“bob”,然后使用 shell 命令列出另一侧的所有用户,果然,bob 出现在那里。

如何确保所有用户都被限制在各自的网站上?

4

3 回答 3

28

最兼容的方法是创建一个包含站点模型外键的用户配置文件模型,然后编写一个自定义身份验证后端,根据该 FK 的值检查当前站点。一些示例代码:

定义您的配置文件模型,例如在 app/models.py 中:

from django.db import models
from django.contrib.sites.models import Site
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    site = models.ForeignKey(Site)

编写您的自定义身份验证后端,继承自默认后端,例如在 app/auth_backend.py 中:

from django.contrib.auth.backends import ModelBackend
from django.contrib.sites.models import Site

class SiteBackend(ModelBackend):
    def authenticate(self, **credentials):
        user_or_none = super(SiteBackend, self).authenticate(**credentials)
        if user_or_none and user_or_none.userprofile.site != Site.objects.get_current():
            user_or_none = None
        return user_or_none

    def get_user(self, user_id):
        try:
            return User.objects.get(
                pk=user_id, userprofile__site=Site.objects.get_current())
        except User.DoesNotExist:
            return None

此身份验证后端假定所有用户都有个人资料;您需要确保您的用户创建/注册过程始终创建一个。

覆盖的authenticate方法确保用户只能登录正确的站点。get_user每次请求时都会调用该方法,以根据用户会话中存储的身份验证信息从数据库中获取用户;我们的覆盖确保用户不能登录站点 A,然后使用相同的会话 cookie 来获得对站点 B 的未经授权的访问。(感谢 Jan Wrobel 指出需要处理后一种情况。)

于 2009-09-10T15:12:32.443 回答
3

您可以插入考虑站点 ID 的自己的授权和身份验证后端。

请参阅django 文档和身份验证后端参考中的其他身份验证源

除此之外,如果您的 django 源代码太旧,您可以随时修改 authenticate() 或 login() 代码。毕竟……这难道不是开源的奇迹之一。请注意,这样做可能会影响与其他模块的兼容性。

希望这可以帮助。

于 2009-09-10T09:09:02.443 回答
-1

你必须知道,很多人抱怨 Django 默认授权系统和权限——它有简单的对象规则,用于对象的实例——这意味着什么,不编写任何代码是不可能的。

但是,有一些授权钩子可以帮助您实现此目标,例如:

看看那里: http ://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py 和类权限。

您可以添加自己的权限并为它们定义规则(用户和 ContentType 有一个 ForeignKey)。

然而2,如果没有猴子补丁/更改某些方法可能会很困难。

于 2009-09-10T13:20:00.833 回答