First working version of the shared web login.
This commit is contained in:
parent
81170b69d0
commit
a31441b3ce
9 changed files with 130 additions and 8 deletions
|
|
@ -6,6 +6,7 @@ import time
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from random import getrandbits
|
from random import getrandbits
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.auth import authenticate
|
||||||
from evennia.players.models import PlayerDB
|
from evennia.players.models import PlayerDB
|
||||||
from evennia.objects.models import ObjectDB
|
from evennia.objects.models import ObjectDB
|
||||||
from evennia.server.models import ServerConfig
|
from evennia.server.models import ServerConfig
|
||||||
|
|
@ -148,17 +149,15 @@ def create_normal_player(session, name, password):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Match account name and check password
|
# Match account name and check password
|
||||||
player = PlayerDB.objects.get_player_from_name(name)
|
player = authenticate(username=name, password=password)
|
||||||
pswd = None
|
|
||||||
if player:
|
|
||||||
pswd = player.check_password(password)
|
|
||||||
|
|
||||||
if not (player and pswd):
|
if not player:
|
||||||
# No playername or password match
|
# No playername or password match
|
||||||
session.msg("Incorrect login information given.")
|
session.msg("Incorrect login information given.")
|
||||||
# this just updates the throttle
|
# this just updates the throttle
|
||||||
_throttle(session)
|
_throttle(session)
|
||||||
# calls player hook for a failed login if possible.
|
# calls player hook for a failed login if possible.
|
||||||
|
player = PlayerDB.objects.get_player_from_name(name)
|
||||||
if player:
|
if player:
|
||||||
player.at_failed_login(session)
|
player.at_failed_login(session)
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,16 @@ settings.INPUT_FUNC_MODULES.
|
||||||
"""
|
"""
|
||||||
from future.utils import viewkeys
|
from future.utils import viewkeys
|
||||||
|
|
||||||
|
import importlib
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from evennia.commands.cmdhandler import cmdhandler
|
from evennia.commands.cmdhandler import cmdhandler
|
||||||
|
from evennia.players.models import PlayerDB
|
||||||
from evennia.utils.logger import log_err
|
from evennia.utils.logger import log_err
|
||||||
from evennia.utils.utils import to_str, to_unicode
|
from evennia.utils.utils import to_str, to_unicode
|
||||||
|
|
||||||
|
# django browser sessions
|
||||||
|
BrowserSessionStore = importlib.import_module(settings.SESSION_ENGINE).SessionStore
|
||||||
|
|
||||||
|
|
||||||
# always let "idle" work since we use this in the webclient
|
# always let "idle" work since we use this in the webclient
|
||||||
_IDLE_COMMAND = settings.IDLE_COMMAND
|
_IDLE_COMMAND = settings.IDLE_COMMAND
|
||||||
|
|
@ -35,6 +40,7 @@ _NA = lambda o: "N/A"
|
||||||
|
|
||||||
_ERROR_INPUT = "Inputfunc {name}({session}): Wrong/unrecognized input: {inp}"
|
_ERROR_INPUT = "Inputfunc {name}({session}): Wrong/unrecognized input: {inp}"
|
||||||
|
|
||||||
|
|
||||||
# All global functions are inputfuncs available to process inputs
|
# All global functions are inputfuncs available to process inputs
|
||||||
|
|
||||||
def text(session, *args, **kwargs):
|
def text(session, *args, **kwargs):
|
||||||
|
|
@ -99,6 +105,35 @@ 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:
|
||||||
|
player = PlayerDB.objects.get(pk=uid)
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
session.sessionhandler.login(session, player)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ from evennia.utils.text2html import parse_html
|
||||||
|
|
||||||
_RE_SCREENREADER_REGEX = re.compile(r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE)
|
_RE_SCREENREADER_REGEX = re.compile(r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
class WebSocketClient(Protocol, Session):
|
class WebSocketClient(Protocol, Session):
|
||||||
"""
|
"""
|
||||||
Implements the server-side of the Websocket connection.
|
Implements the server-side of the Websocket connection.
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ from builtins import object
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import weakref
|
import weakref
|
||||||
|
import importlib
|
||||||
from time import time
|
from time import time
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
@ -19,6 +20,8 @@ from evennia.utils.utils import make_iter, lazy_property
|
||||||
from evennia.commands.cmdsethandler import CmdSetHandler
|
from evennia.commands.cmdsethandler import CmdSetHandler
|
||||||
from evennia.server.session import Session
|
from evennia.server.session import Session
|
||||||
|
|
||||||
|
BrowserSessionStore = importlib.import_module(settings.SESSION_ENGINE).SessionStore
|
||||||
|
|
||||||
_GA = object.__getattribute__
|
_GA = object.__getattribute__
|
||||||
_SA = object.__setattr__
|
_SA = object.__setattr__
|
||||||
_ObjectDB = None
|
_ObjectDB = None
|
||||||
|
|
@ -160,6 +163,7 @@ class ServerSession(Session):
|
||||||
"Initiate to avoid AttributeErrors down the line"
|
"Initiate to avoid AttributeErrors down the line"
|
||||||
self.puppet = None
|
self.puppet = None
|
||||||
self.player = None
|
self.player = None
|
||||||
|
self.browserid = None
|
||||||
self.cmdset_storage_string = ""
|
self.cmdset_storage_string = ""
|
||||||
self.cmdset = CmdSetHandler(self, True)
|
self.cmdset = CmdSetHandler(self, True)
|
||||||
|
|
||||||
|
|
@ -220,6 +224,13 @@ class ServerSession(Session):
|
||||||
self.puppet = None
|
self.puppet = None
|
||||||
self.cmdset_storage = settings.CMDSET_SESSION
|
self.cmdset_storage = settings.CMDSET_SESSION
|
||||||
|
|
||||||
|
if self.browserid:
|
||||||
|
# this is only set by a webclient inputcommand.
|
||||||
|
bsession = BrowserSessionStore(session_key=self.browserid)
|
||||||
|
bsession["logged_in"] = player.id # this also saves the bsession
|
||||||
|
bsession.save()
|
||||||
|
print ("serversession.login:", bsession.session_key)
|
||||||
|
|
||||||
# Update account's last login time.
|
# Update account's last login time.
|
||||||
self.player.last_login = timezone.now()
|
self.player.last_login = timezone.now()
|
||||||
self.player.save()
|
self.player.save()
|
||||||
|
|
|
||||||
|
|
@ -369,6 +369,10 @@ class ServerSessionHandler(SessionHandler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if session.logged_in:
|
||||||
|
# don't log in a session that is already logged in.
|
||||||
|
return
|
||||||
|
|
||||||
# we have to check this first before uid has been assigned
|
# we have to check this first before uid has been assigned
|
||||||
# this session.
|
# this session.
|
||||||
|
|
||||||
|
|
@ -589,6 +593,17 @@ class ServerSessionHandler(SessionHandler):
|
||||||
return sessions[0] if len(sessions) == 1 else sessions
|
return sessions[0] if len(sessions) == 1 else sessions
|
||||||
sessions_from_character = sessions_from_puppet
|
sessions_from_character = sessions_from_puppet
|
||||||
|
|
||||||
|
def sessions_from_browserid(self, browserid):
|
||||||
|
"""
|
||||||
|
Given a browserid, return all sessions having this id.
|
||||||
|
|
||||||
|
Args
|
||||||
|
browserid (str): The browserid hash
|
||||||
|
|
||||||
|
"""
|
||||||
|
return [session for session in self.values()
|
||||||
|
if session.browserid and session.browserid == browserid]
|
||||||
|
|
||||||
def announce_all(self, message):
|
def announce_all(self, message):
|
||||||
"""
|
"""
|
||||||
Send message to all connected sessions
|
Send message to all connected sessions
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,7 @@ An "emitter" object must have a function
|
||||||
open = true;
|
open = true;
|
||||||
ever_open = true;
|
ever_open = true;
|
||||||
Evennia.emit('connection_open', ["websocket"], event);
|
Evennia.emit('connection_open', ["websocket"], event);
|
||||||
|
Evennia.msg('browser_sessid', [browser_sessid], {});
|
||||||
};
|
};
|
||||||
// Handle Websocket close event
|
// Handle Websocket close event
|
||||||
websocket.onclose = function (event) {
|
websocket.onclose = function (event) {
|
||||||
|
|
@ -308,6 +309,7 @@ An "emitter" object must have a function
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
log ("connection_open", ["AJAX/COMET"], data);
|
log ("connection_open", ["AJAX/COMET"], data);
|
||||||
|
Evennia.msg("browser_sessid", [browser_sessid], {});
|
||||||
client_hash = data.suid;
|
client_hash = data.suid;
|
||||||
stop_polling = false;
|
stop_polling = false;
|
||||||
poll();
|
poll();
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,12 @@ JQuery available.
|
||||||
var wsactive = false;
|
var wsactive = false;
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if browser_sessid %}
|
||||||
|
var browser_sessid = "{{browser_sessid}}";
|
||||||
|
{% else %}
|
||||||
|
var browser_sessid = false;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if websocket_url %}
|
{% if websocket_url %}
|
||||||
var wsurl = "{{websocket_url}}:{{websocket_port}}";
|
var wsurl = "{{websocket_url}}:{{websocket_port}}";
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@ page and serve it eventual static content.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.contrib.auth import login
|
||||||
|
|
||||||
|
from evennia.server.sessionhandler import SESSION_HANDLER
|
||||||
from evennia.players.models import PlayerDB
|
from evennia.players.models import PlayerDB
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -14,9 +16,31 @@ def webclient(request):
|
||||||
"""
|
"""
|
||||||
Webclient page template loading.
|
Webclient page template loading.
|
||||||
"""
|
"""
|
||||||
|
print ("webclient session:", request.session.session_key, request.user, request.user.is_authenticated())
|
||||||
|
|
||||||
nsess = len(PlayerDB.objects.get_connected_players()) or "none"
|
browser_session = request.session
|
||||||
# as an example we send the number of connected players to the template
|
browserid = request.session.session_key
|
||||||
pagevars = {'num_players_connected': nsess}
|
player = request.user
|
||||||
|
# check if user has authenticated to website
|
||||||
|
if player.is_authenticated():
|
||||||
|
print ("webclient: player auth, trying to connect sessions")
|
||||||
|
# Try to login all the player's webclient sessions - only
|
||||||
|
# unloggedin ones will actually be logged in.
|
||||||
|
for session in SESSION_HANDLER.sessions_from_browserid(browserid):
|
||||||
|
print ("session to connect:", session)
|
||||||
|
if session.protocol_key in ("websocket", "ajax/comet"):
|
||||||
|
SESSION_HANDLER.login(session, player)
|
||||||
|
session.browserid = browser_session.session_key
|
||||||
|
browser_session["logged_in"] = player.id
|
||||||
|
elif browser_session.get("logged_in"):
|
||||||
|
# The webclient has previously registered a login to this browser_session
|
||||||
|
print ("webclient: browser_session logged in, trying to login")
|
||||||
|
player = PlayerDB.objects.get(browser_session.get("uid"))
|
||||||
|
login(player, request)
|
||||||
|
else:
|
||||||
|
browser_session["logged_in"] = False
|
||||||
|
|
||||||
|
# make sure to store the browser session's hash so the webclient can get to it
|
||||||
|
pagevars = {'browser_sessid': request.session.session_key}
|
||||||
|
|
||||||
return render(request, 'webclient.html', pagevars)
|
return render(request, 'webclient.html', pagevars)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ from evennia import SESSION_HANDLER
|
||||||
from evennia.objects.models import ObjectDB
|
from evennia.objects.models import ObjectDB
|
||||||
from evennia.players.models import PlayerDB
|
from evennia.players.models import PlayerDB
|
||||||
|
|
||||||
|
from django.contrib.auth import login
|
||||||
|
|
||||||
_BASE_CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
|
_BASE_CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -21,6 +23,33 @@ def page_index(request):
|
||||||
"""
|
"""
|
||||||
Main root page.
|
Main root page.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# handle webclient-website shared login
|
||||||
|
|
||||||
|
browser_session = request.session
|
||||||
|
browserid = request.session.session_key
|
||||||
|
player = request.user
|
||||||
|
# check if user has authenticated to website
|
||||||
|
if player.is_authenticated():
|
||||||
|
# Try to login all the player's webclient sessions - only
|
||||||
|
# unloggedin ones will actually be logged in.
|
||||||
|
print "website: player auth, trying to connect sessions"
|
||||||
|
for session in SESSION_HANDLER.sessions_from_browserid(browserid):
|
||||||
|
print "session to connect:", session
|
||||||
|
if session.protocol_key in ("websocket", "ajax/comet"):
|
||||||
|
SESSION_HANDLER.login(session, player)
|
||||||
|
session.browserid = browser_session.session_key
|
||||||
|
browser_session["logged_in"] = player.id
|
||||||
|
elif browser_session.get("logged_in"):
|
||||||
|
# The webclient has previously registered a login to this browser_session
|
||||||
|
print "website: browser_session logged in, trying to login"
|
||||||
|
player = PlayerDB.objects.get(id=browser_session.get("logged_in"))
|
||||||
|
login(request, player)
|
||||||
|
else:
|
||||||
|
browser_session["logged_in"] = None
|
||||||
|
|
||||||
|
print ("website session:", request.session.session_key, request.user, request.user.is_authenticated())
|
||||||
|
|
||||||
# Some misc. configurable stuff.
|
# Some misc. configurable stuff.
|
||||||
# TODO: Move this to either SQL or settings.py based configuration.
|
# TODO: Move this to either SQL or settings.py based configuration.
|
||||||
fpage_player_limit = 4
|
fpage_player_limit = 4
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue