Add smarter shared login on website/webclient. Resolves #1063.

This makes it so that logging into the website will auto-log you
into the webclient and vice-versa when you refresh the page. But if
you log out of the web client will have to manually log in again. If
you log out of the website and reload the webclient page you will have
to log back into the client too (this is because logging out of the
website flushes the browser session, it doesn't seem worth the effort
to override django.auth in this).
This commit is contained in:
Griatch 2017-08-20 20:36:35 +02:00
parent 0ac190b6ea
commit cdac9678b9
7 changed files with 20 additions and 67 deletions

View file

@ -137,32 +137,6 @@ def default(session, cmdname, *args, **kwargs):
log_err(err) log_err(err)
def browser_sessid(session, *args, **kwargs):
"""
This is a utility function for the webclient (only) to communicate its
current browser session hash. This is important in order to link
the browser session to the evennia session. Only the very first
storage request will be accepted, the following ones will be ignored.
Args:
browserid (str): Browser session hash
"""
if not session.browserid:
print "stored browserid:", session, args[0]
session.browserid = args[0]
if not session.logged_in:
# automatic log in if the django browser session already authenticated.
browsersession = BrowserSessionStore(session_key=args[0])
uid = browsersession.get("logged_in", None)
if uid:
try:
account = AccountDB.objects.get(pk=uid)
except Exception:
return
session.sessionhandler.login(session, account)
def client_options(session, *args, **kwargs): def client_options(session, *args, **kwargs):
""" """
This allows the client an OOB way to inform us about its name and capabilities. This allows the client an OOB way to inform us about its name and capabilities.

View file

@ -268,8 +268,9 @@ class PortalSessionHandler(SessionHandler):
data (dict): The session sync data. data (dict): The session sync data.
""" """
session.at_login() print("server_logged_in: %s: %s" % (session, data))
session.load_sync_data(data) session.load_sync_data(data)
session.at_login()
def server_session_sync(self, serversessions, clean=True): def server_session_sync(self, serversessions, clean=True):
""" """

View file

@ -42,7 +42,7 @@ class WebSocketClient(Protocol, Session):
client_address = client_address[0] if client_address else None client_address = client_address[0] if client_address else None
self.init_session("websocket", client_address, self.factory.sessionhandler) self.init_session("websocket", client_address, self.factory.sessionhandler)
def get_browser_session(self): def get_client_session(self):
""" """
Get the Client browser session (used for auto-login based on browser session) Get the Client browser session (used for auto-login based on browser session)
@ -67,9 +67,8 @@ class WebSocketClient(Protocol, Session):
the ws handshake and validation has completed fully. the ws handshake and validation has completed fully.
""" """
csession = self.get_browser_session() csession = self.get_client_session()
uid = csession and csession.get("webclient_authenticated_uid", None) uid = csession and csession.get("webclient_authenticated_uid", None)
print("In validationMade csession uid=", uid)
if uid: if uid:
# the client session is already logged in. # the client session is already logged in.
self.uid = uid self.uid = uid
@ -95,8 +94,8 @@ class WebSocketClient(Protocol, Session):
if csession: if csession:
print("In disconnect: csession uid=%s" % csession.get("webclient_authenticated_uid", None)) print("In disconnect: csession uid=%s" % csession.get("webclient_authenticated_uid", None))
#csession["webclient_authenticated_uid"] = None csession["webclient_authenticated_uid"] = None
#csession.save() csession.save()
self.logged_in = False self.logged_in = False
self.connectionLost(reason) self.connectionLost(reason)
@ -138,8 +137,7 @@ class WebSocketClient(Protocol, Session):
return self.transport.write(line) return self.transport.write(line)
def at_login(self): def at_login(self):
csession = self.get_browser_session() csession = self.get_client_session()
print("Weblient at_login. Session: %s" % csession.session_key)
if csession: if csession:
csession["webclient_authenticated_uid"] = self.uid csession["webclient_authenticated_uid"] = self.uid
csession.save() csession.save()

View file

@ -20,8 +20,6 @@ from evennia.commands.cmdsethandler import CmdSetHandler
from evennia.server.session import Session from evennia.server.session import Session
from evennia.scripts.monitorhandler import MONITOR_HANDLER from evennia.scripts.monitorhandler import MONITOR_HANDLER
ClientSessionStore = importlib.import_module(settings.SESSION_ENGINE).SessionStore
_GA = object.__getattribute__ _GA = object.__getattribute__
_SA = object.__setattr__ _SA = object.__setattr__
_ObjectDB = None _ObjectDB = None
@ -227,15 +225,6 @@ class ServerSession(Session):
self.puppet = None self.puppet = None
self.cmdset_storage = settings.CMDSET_SESSION self.cmdset_storage = settings.CMDSET_SESSION
if self.csessid:
# An existing client sessid is registered, thus a matching
# Client Session must also exist. Update it so the website
# can also see we are logged in.
csession = ClientSessionStore(session_key=self.csessid)
if not csession.get("logged_in"):
csession["logged_in"] = account.id
csession.save()
# Update account's last login time. # Update account's last login time.
self.account.last_login = timezone.now() self.account.last_login = timezone.now()
self.account.save() self.account.save()

View file

@ -476,7 +476,8 @@ class ServerSessionHandler(SessionHandler):
if not testmode: if not testmode:
self.server.amp_protocol.send_AdminServer2Portal(session, self.server.amp_protocol.send_AdminServer2Portal(session,
operation=SLOGIN, operation=SLOGIN,
sessiondata={"logged_in": True}) sessiondata={"logged_in": True,
"uid": session.uid})
account.at_post_login(session=session) account.at_post_login(session=session)
def disconnect(self, session, reason="", sync_portal=True): def disconnect(self, session, reason="", sync_portal=True):

View file

@ -26,26 +26,22 @@ def _shared_login(request):
website_uid = csession.get("website_authenticated_uid", None) website_uid = csession.get("website_authenticated_uid", None)
webclient_uid = csession.get("webclient_authenticated_uid", None) webclient_uid = csession.get("webclient_authenticated_uid", None)
print("webclient website_uid=%s, webclient_uid=%s, session_key=%s" % (website_uid, webclient_uid, csession.session_key))
# check if user has authenticated to website # check if user has authenticated to website
if csession.session_key is None: if not csession.session_key:
# this is necessary to build the sessid key # this is necessary to build the sessid key
print("Webclient created a new browser session key")
csession.save() csession.save()
if webclient_uid: if webclient_uid:
# The webclient has previously registered a login to this browser_session # The webclient has previously registered a login to this browser_session
if not account.is_authenticated(): if not account.is_authenticated() and not website_uid:
# not logged into website account = AccountDB.objects.get(id=webclient_uid)
if website_uid is None: try:
account = AccountDB.objects.get(id=webclient_uid) # calls our custom authenticate in web/utils/backends.py
try: account = authenticate(autologin=account)
# calls our custom authenticate in web/utils/backends.py login(request, account)
account = authenticate(autologin=account) csession["website_authenticated_uid"] = webclient_uid
login(request, account) except AttributeError:
csession["website_authenticated_uid"] = webclient_uid logger.log_trace()
except AttributeError:
logger.log_trace()
def webclient(request): def webclient(request):

View file

@ -28,17 +28,11 @@ def _shared_login(request):
""" """
csession = request.session csession = request.session
account = request.user account = request.user
# these can have 3 values:
# None - previously unused (auto-login)
# False - actively logged out (don't auto-login)
# <uid> - logged in User/Account id
website_uid = csession.get("website_authenticated_uid", None) website_uid = csession.get("website_authenticated_uid", None)
webclient_uid = csession.get("webclient_authenticated_uid", None) webclient_uid = csession.get("webclient_authenticated_uid", None)
print("website website_uid=%s, webclient_uid=%s, session_key=%s" % (website_uid, webclient_uid, csession.session_key))
if csession.session_key is None: if not csession.session_key:
# this is necessary to build the sessid key # this is necessary to build the sessid key
print("Website created a new browser session key")
csession.save() csession.save()
if account.is_authenticated(): if account.is_authenticated():