Принудительная аутентификация любым пользователем

В целях отладки проекта мне понадобилось быстро просматривать сайт глазами конкретного пользователя. Для этого я решил написать отдельный view, в который передаю id пользователя. В документации Django написано, что для авторизации пользователя нужно сначала выполнить фунцию authenticate из модуля django.contrib.auth, а затем login.

authenticate занимается тем, что по очереди до первого успеха опрашивает все доступные бэкенды аутентификации, перечисленные в settings.AUTHENTICATION_BACKENDS, передавая им параметры собственного вызова. В случае успеха backend должен вернуть объект типа django.contrib.auth.User.models, в противном случае None.

login получает в параметрах request и user и синхронизирует request.user и user, в зависимости от того, что из них является None.

Трудность заключается в том, что стандартный backend аутентификации Django, принимает в качестве параметров имя пользователя и незашифрованный пароль. Незашифрованные пароли пользователей мне неизвестны. Пришлось отказаться от функции authenticate и передавать в login пользователя полученного непосредственно по запросу User.objects.get(pk=user_id).

Однако, после такого финта, Django стал возмущаться на то, что у объекта пользователя передаваемого в функцию login нет атрибута backend, в который функция authenticate (которую я не вызываю) должна была записать имя успешно сработавшего бэкенда аутентификации.

Мне помогло прописывание стандартного бэкенда. Таким образом код приобрёл следующую форму:


def loginas(request,user_id):
if not getattr(settings,'LOGIN_DEBUG',False):
raise AccessDeniedException('/')
else:
user = User.objects.get(pk=user_id)
user.backend = 'django.contrib.auth.backends.ModelBackend'
auth.login(request, user)
return HttpResponseRedirect(user.get_profile().get_absolute_url())
e

def loginas(request,user_id):
if not getattr(settings,’LOGIN_DEBUG’,False):
raise AccessDeniedException(‘/’)
else:
user = User.objects.get(pk=user_id)
user.backend = ‘django.contrib.auth.backends.ModelBackend’
auth.login(request, user)
return HttpResponseRedirect(user.get_profile().get_absolute_url())
e


C помощью опции settings.LOGIN_DEBUG можно быстро отлючать/включать отладочную функцию логина.

Ну, и в завершение я чуть-чуть изменил свой inclusion tag, который использую в шаблонах для отображения ссылки на переданный объект. Теперь этот тэг выводит звёздочку рядом с именем пользователя, которая является ссылкой на вышеописанный view.

Собственно, вот сам код тэга:


@register.inclusion_tag('site/link.html')
def link(object,base=u''):
user_id = None
if isinstance(object,User):
object = object.get_profile()
if isinstance(object,UserProfile):
if getattr(settings,'LOGIN_DEBUG',False):
user_id = object.user.id
url = object.get_absolute_url()
url = base + url
anchor = smart_unicode(object)
return {
'user_id': user_id,
'url': url,
'anchor': anchor}

@register.inclusion_tag(‘site/link.html’)
def link(object,base=u”):
user_id = None
if isinstance(object,User):
object = object.get_profile()
if isinstance(object,UserProfile):
if getattr(settings,’LOGIN_DEBUG’,False):
user_id = object.user.id
url = object.get_absolute_url()
url = base + url
anchor = smart_unicode(object)
return {
‘user_id’: user_id,
‘url’: url,
‘anchor’: anchor}

и шаблон:


<a href="{{ url }}">{{ anchor|escape }}</a>
{% if user_id %}
<a href="/debug/loginas/{{ user_id }}/">*</a>
{% endif %}

<a href=”{{ url }}”>{{ anchor|escape }}</a>
{% if user_id %}
<a href=”/debug/loginas/{{ user_id }}/”>*</a>
{% endif %}


UPD:
А вот реализация для middleware, здесь ID пользователя, которым нужно залогиниться, передаётся просто через GET-параметр loginas


from django.http import HttpResponseRedirect
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth import login

class DebugLoginMiddleware(object):
def process_request(self, request):
if not getattr(settings,'LOGIN_DEBUG',False):
return None
try:
id = int(request.GET.get('loginas',0))
except ValueError:
return None
try:
user = User.objects.get(pk=id)
except User.DoesNotExist:
return None
user.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, user)
return None

from django.http import HttpResponseRedirect
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth import login

class DebugLoginMiddleware(object):
def process_request(self, request):
if not getattr(settings,’LOGIN_DEBUG’,False):
return None
try:
id = int(request.GET.get(‘loginas’,0))
except ValueError:
return None
try:
user = User.objects.get(pk=id)
except User.DoesNotExist:
return None
user.backend = ‘django.contrib.auth.backends.ModelBackend’
login(request, user)
return None
Add post to:   Delicious Reddit Slashdot Digg Technorati Google
Make comment

Comments

No comments for this post

Required. 30 chars of fewer.

Required.

captcha image Please, enter symbols, which you see on the image