代码之家  ›  专栏  ›  技术社区  ›  ibz

管理员模拟Django用户

  •  20
  • ibz  · 技术社区  · 16 年前

    我有一个Django应用程序。当作为管理员用户登录时,我希望能够在URL中传递一个秘密参数,并使整个站点的行为就像我是另一个用户一样。

    假设我有网址 /my-profile/ 显示当前登录用户的配置文件。我想做一些像这样的事情 /my-profile/?__user_id=123 让底层视图相信我实际上是ID为123的用户(因此 那个 用户配置文件)。

    我为什么要那样?

    只是因为复制某些只出现在单个用户帐户中的bug要容易得多。

    我的问题是:

    1. 进行此操作时,我是否应该考虑任何安全问题?请注意,我(显然)只想为管理员用户提供此功能,而且我们的管理员用户可以完全访问源代码、数据库等,所以这不是真正的“后门”;就这么定了 访问用户的帐户。

    6 回复  |  直到 13 年前
        1
  •  39
  •   Charles Offenbacher    15 年前

    我还没有足够的声誉来编辑或回复(我想),但我发现,虽然ionaut的解决方案在简单的情况下有效,但对我来说,一个更强大的解决方案是使用会话变量。这样,即使是AJAX请求也可以正确地提供,而无需修改请求URL以包含GET模拟参数。

    class ImpersonateMiddleware(object):
        def process_request(self, request):
            if request.user.is_superuser and "__impersonate" in request.GET:
                request.session['impersonate_id'] = int(request.GET["__impersonate"])
            elif "__unimpersonate" in request.GET:
                del request.session['impersonate_id']
            if request.user.is_superuser and 'impersonate_id' in request.session:
                request.user = User.objects.get(id=request.session['impersonate_id'])
    

    用法:

    log in: http://localhost/?__impersonate=[USERID]
    log out (back to admin): http://localhost/?__unimpersonate=True
    
        2
  •  14
  •   Hamish Downer JKP    11 年前

    django packages page for user switching

    • django-hijack 在管理员的用户列表中放置一个“劫持”按钮,并在页面顶部放置一个小按钮,用于劫持帐户。
    • impostor 意味着您可以使用用户名“我是其他人”和您自己的密码登录
    • django-impersonate 设置URL以开始模拟用户、停止、搜索等
        3
  •  10
  •   ibz    16 年前

    我用一个简单的中间件解决了这个问题。它还处理重定向(也就是说,在重定向过程中保留GET参数)。这是:

    class ImpersonateMiddleware(object):
        def process_request(self, request):
            if request.user.is_superuser and "__impersonate" in request.GET:
                request.user = models.User.objects.get(id=int(request.GET["__impersonate"]))
    
        def process_response(self, request, response):
            if request.user.is_superuser and "__impersonate" in request.GET:
                if isinstance(response, http.HttpResponseRedirect):
                    location = response["Location"]
                    if "?" in location:
                        location += "&"
                    else:
                        location += "?"
                    location += "__impersonate=%s" % request.GET["__impersonate"]
                    response["Location"] = location
            return response
    
        4
  •  1
  •   eMBee    12 年前

    我不认为这是一个安全漏洞,就像在unix机器上使用su-someuser作为root一样。root用户或具有root/admin数据库访问权限的django管理员可以伪造任何东西,如果他/她愿意的话。风险只存在于django admin帐户被破解时,破解者可能会通过成为另一个用户,然后以用户身份假装操作来隐藏跟踪。

    是的,它可能被称为后门,但正如ibz所说,管理员无论如何都可以访问数据库。在这种情况下对数据库进行更改也是一个后门。

        5
  •  1
  •   davetw12    9 年前

    @Charles Ofenbacher的答案非常适合模拟未通过令牌进行身份验证的用户。但是,它不适用于使用令牌身份验证的客户端应用程序。要让用户模拟使用令牌处理应用程序,必须直接在模拟中间件中设置HTTP_授权头。我的答案基本上抄袭了Charles的答案,并添加了手动设置标题的行。

    class ImpersonateMiddleware(object):
        def process_request(self, request):
            if request.user.is_superuser and "__impersonate" in request.GET:
                request.session['impersonate_id'] = int(request.GET["__impersonate"])
            elif "__unimpersonate" in request.GET:
                del request.session['impersonate_id']
            if request.user.is_superuser and 'impersonate_id' in request.session:
                request.user = User.objects.get(id=request.session['impersonate_id'])
                # retrieve user's token
                token = Token.objects.get(user=request.user)
                # manually set authorization header to user's token as it will be set to that of the admin's (assuming the admin has one, of course)
                request.META['HTTP_AUTHORIZATION'] = 'Token {0}'.format(token.key)
    
        6
  •  -2
  •   Lennart Regebro    16 年前

    设置为在同一服务器上有两个不同的主机名。例如,如果您在本地执行此操作,则可以连接127.0.0.1或localhost。您的浏览器将看到这三个不同的站点,您可以使用不同的用户登录。这同样适用于您的站点。