如何在"站点"框架支持的多个Django站点中获得独特用户?

wes*_*ark 25 django django-sites

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

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

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

Car*_*yer 27

最兼容的方法是创建一个包含Site模型外键的用户Profile模型,然后编写一个自定义auth后端,根据该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)
Run Code Online (Sandbox Code Playgroud)

编写自定义身份验证后端,继承默认后端,让我们说在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
Run Code Online (Sandbox Code Playgroud)

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

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

  • 不,这个后端只做部分工作.它不允许一个站点的用户登录到另一个站点,这是不够的.用户可以登录站点A并手动复制身份验证cookie以将其发送给站点B.此类cookie将被识别为有效并且用户将登录(仅当没有有效的会话cookie时才会调用身份验证后端).要完成解决方案,您需要一个中间件,该中间件将针对您的站点的每个请求进行调用,并且将检查用户是否登录到与请求相关的站点,而不是其他站点. (4认同)
  • @JanWrobel我相信,您可以在身份验证后端的`get_user`方法中实现类似的检查,而不是单独的中间件.每次请求都会调用此方法,而不仅仅是在登录时.我会更新答案以包含此内容; 谢谢你指出遗漏. (4认同)
  • @CarlMeyer覆盖get_user工作,确实比单独的中间件简单得多.谢谢! (2认同)
  • 但如何处理独特的字段呢?如何在不同的站点中添加两个用户名为“Arti”的用户? (2认同)