Форум сайта python.su
Добрый день. Разбираюсь с новой для себя областью веб сокетов. Выбрал связку tornado+sockjs+django
столкнулся с одной серьезной трудностью, связанной с идентификацией пользователей при обмене сообщений между сервером торнадо и клиентом. Во множестве примеров используется идентификация пользователя спомощью id сессии. Но насколько я понял, sockjs на сервере не принимает никаких куков.
Вот типичный код из туториалов:
def get_session(session_key): return _engine.SessionStore(session_key) def get_user(session): class Dummy(object): pass django_request = Dummy() django_request.session = session return django.contrib.auth.get_user(django_request) class Connection (SockJSConnection): def on_open(self, info): """ Определяем сессию django. """ self.django_session = get_session(info.get_cookie('sessionid').value) self.user = get_user(self.django_session)
self.django_session = get_session(info.get_cookie('sessionid').value)
<script language="javascript"> var sock = new SockJS('/echo'); // Lets assume we invented simple protocol, where first word is a command name and second is a payload. sock.onconnect = function() { sock.send('auth,xxx'); sock.send('echo,bar'); }; </script>
class EchoConnection(SockJSConnection): def on_open(self, info): self.authenticated = False def on_message(self, msg): pack, data = msg.split(',', 1) # Ignore all packets except of 'auth' if user is not yet authenticated if not self.authenticated and pack != 'auth': return if pack == 'auth': # Decrypt user_id (or user name - you decide). You might want to add salt to the token as well. user_id = des_decrypt(data, secret_key) # Validate user_id here by making DB call, etc. user = get_user(user_id) if user is None and user.is_active: self.send('error,Invalid user!') return self.authenticated = True elif pack == 'echo': self.send(data)
Отредактировано in (Июнь 26, 2014 21:27:43)
Офлайн
Напишу, о том как выкрутился. Не знаю может быть это избыточное решение. Покритикуете тогда, если что не так.
Прежде всего мне не нравилось в туториалах то, что есть какие непонятные манипуляции с фековым реквестом, который необходим для вытаскивания айдишника юзера. В сессиях джанго,в свою очередь, айдишник хранится где-то в недрах сессии, практически прозапас, и нет никакого официального апи чтобы вытаскивать ассоциированного с сессией пользователя. Поэтому манипуляции с реквестом, совсем не во всех случаях будут давать айдишник авторизованного пользователя вместо чего будет возвращать айдишник анонима.
Поэтому этот сильно пахнущий код я выбросил на помойку:
def get_user(session): class Dummy(object): pass django_request = Dummy() django_request.session = session return django.contrib.auth.get_user(django_request)
import redis strict_redis = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True) @sensitive_post_parameters() @csrf_protect @never_cache def login(request, template_name='registration/login.html', redirect_field_name=REDIRECT_FIELD_NAME, authentication_form=AuthenticationForm, current_app=None, extra_context=None): """ Displays the login form and handles the login action. """ redirect_to = request.REQUEST.get(redirect_field_name, '') if request.method == "POST": form = authentication_form(request, data=request.POST) if form.is_valid(): # Ensure the user-originating redirection url is safe. if not is_safe_url(url=redirect_to, host=request.get_host()): redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL) # Okay, security check complete. Log the user in. auth_login(request, form.get_user()) # мой код дополняющий кеширование сессий ассоциирующихся с айди юзеров session_key = request.session.session_key user_id = str(form.get_user().id) strict_redis.hset(ls.CHAT_REDIS_SESSIONS_STORAGE, session_key, user_id) return HttpResponseRedirect(redirect_to) else: form = authentication_form(request) current_site = get_current_site(request) context = { 'form': form, redirect_field_name: redirect_to, 'site': current_site, 'site_name': current_site.name, } if extra_context is not None: context.update(extra_context) return TemplateResponse(request, template_name, context, current_app=current_app)
MIDDLEWARE_CLASSES = ( """ другие middlewares""" 'registration.middleware.cookies_test.TestCookieMiddleware' )
class TestCookieMiddleware(object): def process_view(self, request, view_func, view_args, view_kwargs): request.session.set_test_cookie() return
def get_user(session_key): cached_id = strict_redis.hget(ls.CHAT_REDIS_SESSIONS_STORAGE, session_key) user = User.objects.get(id=cached_id) return user
ws.onopen = function() { ws.send ('auth,' + sessionid) };
Отредактировано in (Июнь 28, 2014 01:02:01)
Офлайн
Столкнулся с такой же задачей, пост выше очень помог, спасибо.
Если запускать торнадо как manage.py команду, то таких проблем не возникает.
Отредактировано Grayson (Авг. 31, 2016 21:55:33)
Офлайн