11đź‘Ť
I solved this with a simple middleware. It also handles redirects (that is, the GET parameter is preserved during a redirect). Here it is:
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
42đź‘Ť
I don’t have enough reputation to edit or reply yet (I think), but I found that although ionaut’s solution worked in simple cases, a more robust solution for me was to use a session variable. That way, even AJAX requests are served correctly without modifying the request URL to include a GET impersonation parameter.
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'])
Usage:
log in: http://localhost/?__impersonate=[USERID]
log out (back to admin): http://localhost/?__unimpersonate=True
- [Django]-ImportError: cannot import name 'six' from 'django.utils'
- [Django]-Django Model Field Default to Null
- [Django]-Can I have a Django form without Model
15đź‘Ť
It looks like quite a few other people have had this problem and have written re-usable apps to do this and at least some are listed on the django packages page for user switching. The most active at time of writing appear to be:
- django-hijack puts a “hijack” button in the user list in the admin, along with a bit at the top of page for while you’ve hijacked an account.
- impostor means you can login with username “me as other” and your own password
- django-impersonate sets up URLs to start impersonating a user, stop, search etc
- [Django]-Django 1.7.1 Makemigrations fails when using lambda as default for attribute
- [Django]-How to print BASE_DIR from settings.py from django app in terminal?
- [Django]-Inject errors into already validated form?
2đź‘Ť
@Charles Offenbacher’s answer is great for impersonating users who are not being authenticated via tokens. However, it will not work with clients side apps that use token authentication. To get user impersonation to work with apps using tokens, one has to directly set the HTTP_AUTHORIZATION header in the Impersonate Middleware. My answer basically plagiarizes Charles’s answer and adds lines for manually setting said header.
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)
- [Django]-Get django object id based on model attribute
- [Django]-Bypass confirmation prompt for pip uninstall
- [Django]-In the Django admin interface, is there a way to duplicate an item?
1đź‘Ť
i don’t see how that is a security hole any more than using su – someuser as root on a a unix machine. root or an django-admin with root/admin access to the database can fake anything if he/she wants to. the risk is only in the django-admin account being cracked at which point the cracker could hide tracks by becoming another user and then faking actions as the user.
yes, it may be called a backdoor, but as ibz says, admins have access to the database anyways. being able to make changes to the database in that light is also a backdoor.
- [Django]-Bad request 400: nginx / gunicorn
- [Django]-Building a list in Django templates
- [Django]-Django and postgresql schemas
0đź‘Ť
Based on Charles’ answer, I’ve updated to work with Django 4.2
class ImpersonateMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(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'])
response = self.get_response(request)
return response
- [Django]-'Request header field Authorization is not allowed' error – Tastypie
- [Django]-Django serializer Imagefield to get full URL
- [Django]-Django: TemplateSyntaxError: Could not parse the remainder
0đź‘Ť
You can make something much simpler:
def impersonate(request, name):
assert settings.DEBUG
login(request, user=User.objects.get(username=name), backend=_get_backends(return_tuples=True)[0][1])
return HttpResponseRedirect('/')
I wrote the assert for DEBUG there because this code is clearly only good for local dev work.
- [Django]-Using AuthenticationForm in Django
- [Django]-In the Django admin site, how do I change the display format of time fields?
- [Django]-Best place to clear cache when restarting django server
-3đź‘Ť
Set up so you have two different host names to the same server. If you are doing it locally, you can connect with 127.0.0.1, or localhost, for example. Your browser will see this as three different sites, and you can be logged in with different users. The same works for your site.
So in addition to www.mysite.com you can set up test.mysite.com, and log in with the user there. I often set up sites (with Plone) so I have both www.mysite.com and admin.mysite.com, and only allow access to the admin pages from there, meaning I can log in to the normal site with the username that has the problems.
- [Django]-Django templates: forloop.first and forloop.last
- [Django]-Django: Admin: changing the widget of the field in Admin
- [Django]-Django query filter combining AND and OR with Q objects don't return the expected results