Implement a custom authenticate middleware to correctly handle already-authenticated players in auto-connect webclient mode. Resolves #1037.

This commit is contained in:
Griatch 2016-09-14 22:32:58 +02:00
parent 86f963fa71
commit 07944918f7
3 changed files with 39 additions and 12 deletions

View file

@ -3,16 +3,38 @@ from django.contrib.auth import get_user_model
class CaseInsensitiveModelBackend(ModelBackend): class CaseInsensitiveModelBackend(ModelBackend):
""" """
By default ModelBackend does case _sensitive_ username authentication, which isn't what is By default ModelBackend does case _sensitive_ username
generally expected. This backend supports case insensitive username authentication. authentication, which isn't what is generally expected. This
backend supports case insensitive username authentication.
""" """
def authenticate(self, username=None, password=None): def authenticate(self, username=None, password=None, autologin=None):
User = get_user_model() """
try: Custom authenticate with bypass for auto-logins
user = User.objects.get(username__iexact=username)
if user.check_password(password): Args:
return user username (str, optional): Name of user to authenticate.
password (str, optional): Password of user
autologin (Player, optional): If given, assume this is
an already authenticated player and bypass authentication.
"""
if autologin:
# Note: Setting .backend on player is critical in order to
# be allowed to call django.auth.login(player) later. This
# is necessary for the auto-login feature of the webclient,
# but it's important to make sure Django doesn't change this
# requirement or the name of the property down the line. /Griatch
autologin.backend = "evennia.web.utils.backends.CaseInsensitiveModelBackend"
return autologin
else: else:
return None # In this case .backend will be assigned automatically
except User.DoesNotExist: # somewhere along the # way.
return None Player = get_user_model()
try:
player = Player.objects.get(username__iexact=username)
if player.check_password(password):
return player
else:
return None
except Player.DoesNotExist:
return None

View file

@ -6,7 +6,7 @@ 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 django.contrib.auth import login, authenticate
from evennia.players.models import PlayerDB from evennia.players.models import PlayerDB
from evennia.utils import logger from evennia.utils import logger
@ -33,6 +33,8 @@ def _shared_login(request):
# The webclient has previously registered a login to this browser_session # The webclient has previously registered a login to this browser_session
player = PlayerDB.objects.get(id=sesslogin) player = PlayerDB.objects.get(id=sesslogin)
try: try:
# calls our custom authenticate in web/utils/backends.py
player = authenticate(autologin=player)
login(request, player) login(request, player)
except AttributeError: except AttributeError:
logger.log_trace() logger.log_trace()

View file

@ -7,6 +7,7 @@ templates on the fly.
""" """
from django.contrib.admin.sites import site from django.contrib.admin.sites import site
from django.conf import settings from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.admin.views.decorators import staff_member_required from django.contrib.admin.views.decorators import staff_member_required
from django.shortcuts import render from django.shortcuts import render
@ -39,6 +40,8 @@ def _shared_login(request):
# The webclient has previously registered a login to this csession # The webclient has previously registered a login to this csession
player = PlayerDB.objects.get(id=sesslogin) player = PlayerDB.objects.get(id=sesslogin)
try: try:
# calls our custom authenticate, in web/utils/backend.py
authenticate(autologin=player)
login(request, player) login(request, player)
except AttributeError: except AttributeError:
logger.log_trace() logger.log_trace()