Django 管理员用户假冒
我有一个Django应用。当我以管理员身份登录时,我想在网址中传递一个秘密参数,让整个网站表现得像我是在以另一个用户的身份浏览。
比如说,我有一个网址 /my-profile/
,这个页面显示的是当前登录用户的个人资料。我希望能够像这样使用 /my-profile/?__user_id=123
,让系统认为我实际上是ID为123的用户(这样就能显示出那个用户的个人资料)。
我为什么想这样做呢?
因为这样可以更方便地重现一些只在某个用户账户中出现的bug。
我有几个问题:
实现这样的功能最简单的方法是什么?
在做这个的时候,有没有什么安全方面的考虑?请注意,我(显然)只想让管理员用户使用这个功能,而我们的管理员用户本来就可以完全访问源代码、数据库等,所以这并不算是一个“后门”;它只是让访问用户账户变得更简单。
8 个回答
15
看起来很多人都遇到过这个问题,并且他们写了一些可以重复使用的应用程序来解决这个问题,至少有一些在Django用户切换的包页面上列出了。到目前为止,最活跃的几个应用程序包括:
- django-hijack 在管理员的用户列表中放了一个“劫持”按钮,同时在页面顶部显示你正在劫持某个账户的提示。
- impostor 允许你用用户名“我作为其他人”和自己的密码登录。
- django-impersonate 设置了一些网址,可以开始模仿某个用户、停止模仿、搜索等等。
42
我还没有足够的声望来编辑或回复(我想是这样),但我发现虽然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
11
我用一个简单的中间件解决了这个问题。它还可以处理重定向(也就是说,在重定向过程中,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