Verwenden von Joomla-Konten in einem Django-Projekt

Angenommen, die von Ihren Benutzern verwendete Website ist in Joomla geschrieben. Um jedoch ein neues Produkt für Ihr Publikum zu erstellen, haben Sie das Python / Django-Bundle ausgewählt.


Daher müssen Sie Benutzerkonten aus der Joomla-Datenbank in Django verwenden.


Das Problem ist jedoch, dass Joomla und Django unterschiedliche Kennwort-Hashing-Algorithmen verwenden, sodass nur das Kopieren der Konten fehlschlägt.


Nachdem ich die Django-Dokumentation gelesen, den Stapel übergelaufen und einige Zeit verbracht hatte, erhielt ich die unten beschriebene Lösung, die die empfohlenen Entwicklungspraktiken für Django maximal nutzt.


Warnungen


Diese architektonische Lösung passt möglicherweise nicht zu Ihnen, siehe Diskussion in den Kommentaren .


Um zu verstehen, was in den folgenden Beispielen passiert, müssen Sie die Django-Architektur verstehen.


Ich gehe auch davon aus, dass Sie wissen, wie man ein Django-Projekt bereitstellt, daher beschreibe ich diesen Prozess nicht.


Der Code wird aus einem Arbeitsprojekt kopiert, lässt sich jedoch mit einem Minimum an Änderungen leicht an Ihr Projekt anpassen.


Wahrscheinlich wird dieser Code in der nächsten Hauptversion von Django brechen, das Lösungsprinzip bleibt jedoch dasselbe.


In diesem Handbuch beschreibe ich das Frontend des Autorisierungssystems nicht, da:


  • Welches Front-End Sie haben, hängt von den Anforderungen Ihres Projekts ab (es kann beispielsweise sogar ein Json-API-Endpunkt sein).
  • Diese Informationen sind bereits in den offiziellen Django-Tutorials und verschiedenen Starterartikeln beschrieben

Algorithmus


  • Verbinden Sie die Joomla-Datenbank (DB) mit dem Django-Projekt
  • Erstellen Sie ein JoomlaUser-Modell, das einen Benutzer aus der Joomla-Datenbank darstellt
  • Schreiben Sie eine Funktion check_joomla_password() , die überprüft, ob das eingegebene Kennwort mit dem ursprünglichen Kennwort des Benutzers übereinstimmt.
  • Fügen Sie dem Projekt ein neues Autorisierungs-Backend "Joomla Auth Backend" hinzu, das bei der Autorisierung des Clients in Django das Benutzerkonto aus der Joomla-Datenbank erhält

1. Verbindung zur Joomla-Datenbank:


  • Lesen Sie, wie Django mit mehreren Datenbanken arbeitet
  • /project_name/settings.py der Projekteinstellungsdatei /project_name/settings.py den folgenden Code hinzu, um die Joomla-Datenbank mit unserem Django-Projekt zu verbinden:


     DATABASES = { #    'default': { ... }, 'joomla_db': { 'ENGINE': 'django.db.backends.mysql', 'OPTIONS': {}, 'NAME': 'joomla_database_name', # Don't store passwords in the code, instead use env vars: 'USER': os.environ['joomla_db_user'], 'PASSWORD': os.environ['joomla_db_pass'], 'HOST': 'joomla_db_host, can be localhost or remote IP', 'PORT': '3306', } } 


Bei Bedarf können Sie in derselben Datei mit den Projekteinstellungen die Protokollierung von Datenbankabfragen aktivieren:


 # add logging to see DB requests: LOGGING = { 'version': 1, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'level': 'DEBUG', 'handlers': ['console'], }, }, } 

2. Erstellen Sie ein JoomlaUser-Modell


  • Lesen Sie, wie ein Django-Modell eine vorhandene Datenbank verwenden kann
  • Überlegen Sie, wo Sie den neuen JoomlaUser platzieren möchten.
    In meinem Projekt habe ich eine Anwendung namens "Benutzer" erstellt ( manage.py startapp users ). Es enthält das Autorisierungs-Backend und das Joomla-Benutzermodell.
  • Generieren Sie das Modell automatisch mit inspectdb:
    python manage.py inspectdb live_users --database="joomla_db"
    joomla_db - der Name der Datenbank, die Sie in settings.py/DATABASES ;
    live_users - Name der Tabelle mit Konten.
  • users/models.py Sie Ihr Modell zu users/models.py :


     class JoomlaUser(models.Model): """ Represents our customer from the legacy Joomla database. """ username = models.CharField(max_length=150, primary_key=True) email = models.CharField(max_length=100) password = models.CharField(max_length=100) # you can copy more fields from `inspectdb` output, # but it's enough for the example class Meta: # joomla db user table. WARNING, your case can differs. db_table = 'live_users' # readonly managed = False # tip for the database router app_label = "joomla_users" 


Als nächstes müssen wir sicherstellen, dass das Modell auf die richtige Datenbank zugreift. Fügen Sie dazu dem Projekt einen Router für Abfragen an verschiedene Datenbanken hinzu , der Anforderungen vom JoomlaUser-Modell an die native Datenbank umleitet.


  1. Erstellen Sie die Datei "db_routers.py" im Hauptordner des Projekts (an derselben Stelle, an der sich Ihre "settings.py" befindet):


     # project_name/db_routers.py class DbRouter: """this router makes sure that django uses legacy 'Joomla' database for models, that are stored there (JoomlaUser)""" def db_for_read(self, model, **kwargs): if model._meta.app_label == 'joomla_user': return 'joomla_db' return None def db_for_write(self, model, **kwargs): if model._meta.app_label == 'joomla_user': return 'joomla_db' return None 

  2. Registrieren Sie einen neuen Router in settings.py :


     # ensure that Joomla users are populated from the right database: DATABASE_ROUTERS = ['project_name.db_routers.DbRouter'] 


Jetzt können Sie ein Konto aus der alten Datenbank erhalten.
Starten Sie ein Django-Terminal und versuchen Sie, einen vorhandenen Benutzer python manage.py shell : python manage.py shell


 >>> from users.models import JoomlaUser >>> print(JoomlaUser.objects.get(username='someuser')) JoomlaUser object (someusername) >>> 

Wenn alles funktioniert (Sie sehen den Benutzer), fahren Sie mit dem nächsten Schritt fort. Andernfalls überprüfen Sie die Fehlerausgabe und korrigieren Sie die Einstellungen.


3. Überprüfen Sie das Joomla-Kontokennwort


Joomla speichert keine Benutzerkennwörter, sondern beispielsweise deren Hash
$2y$10$aoZ4/bA7pe.QvjTU0R5.IeFGYrGag/THGvgKpoTk6bTz6XNkY0F2e


Ab Joomla v3.2 werden Benutzerkennwörter mit dem BLOWFISH- Algorithmus verschlüsselt.


Also habe ich Python-Code mit diesem Algorithmus heruntergeladen:


 pip install bcrypt echo bcrypt >> requirements.txt 

Und eine Funktion zum Überprüfen von Passwörtern in der users/backend.py :


 def check_joomla_password(password, hashed): """ Check if password matches the hashed password, using same hashing method (Blowfish) as Joomla >= 3.2 If you get wrong results with this function, check that the Hash starts from prefix "$2y", otherwise it is probably not a blowfish hash :return: True/False """ import bcrypt if password is None: return False # bcrypt requires byte strings password = password.encode('utf-8') hashed = hashed.encode('utf-8') return hashed == bcrypt.hashpw(password, hashed) 

Achtung! Joomla-Versionen unter 3.2 verwenden eine andere Hashing-Methode (md5 + salt), sodass diese Funktion nicht funktioniert. In diesem Fall lesen
Diskussion über Stackoverflow und Erstellen einer Hash-Check-Funktion, die ungefähr so aussieht:


 # WARNING - THIS FUNCTION WAS NOT TESTED WITH REAL JOOMLA USERS # and definitely has some errors def check_old_joomla_password(password, hashed): from hashlib import md5 password = password.encode('utf-8') hashed = hashed.encode('utf-8') if password is None: return False # check carefully this part: hash, salt = hashed.split(':') return hash == md5(password+salt).hexdigest() 

Leider habe ich keine Benutzerbasis aus der alten Version von Joomla zur Hand, daher kann ich diese Funktion nicht für Sie testen.


4. Backend-Benutzerautorisierung Joomla


Jetzt können Sie ein Django-Backend erstellen, um Benutzer aus dem Joomla-Projekt zu autorisieren.


  1. Lesen Sie, wie Sie das Django-Autorisierungssystem ändern


  2. Registrieren Sie ein neues Backend (noch nicht vorhanden) in project/settings.py :


     AUTHENTICATION_BACKENDS = [ # Check if user already in the local DB # by using default django users backend 'django.contrib.auth.backends.ModelBackend', # If user was not found among django users, # use Joomla backend, which: # - search for user in Joomla DB # - check joomla user password # - copy joomla user into Django user. 'users.backend.JoomlaBackend', ] 

  3. Erstellen Sie ein Joomla-Benutzerautorisierungs-Backend in users/backend.py



 from django.contrib.auth.models import User from .models import JoomlaUser def check_joomla_password(password, hashed): # this is a fuction, that we wrote before ... class JoomlaBackend: """ authorize users against Joomla user records """ def authenticate(self, request, username=None, password=None): """ IF joomla user exists AND password is correct: create django user return user object ELSE: return None """ try: joomla_user = JoomlaUser.objects.get(username=username) except JoomlaUser.DoesNotExist: return None if check_joomla_password(password, joomla_user.password): # Password is correct, let's create and return Django user, # identical to Joomla user: # but before let's ensure there is no same username # in DB. That could happen, when user changed password # in Joomla, but Django doesn't know that User.objects.filter(username=username).delete() return User.objects.create_user( username=username, email=joomla_user.email, password=password, # any additional fields from the Joomla user: ... ) # this method is required to match Django Auth Backend interface def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None 

Zusammenfassung


Herzlichen Glückwunsch - jetzt können Benutzer Ihrer vorhandenen Joomla-Site ihre Anmeldeinformationen auf einer neuen Site / Anwendung verwenden.


Als Autorisierung aktiver Benutzer über die neue Schnittstelle werden diese einzeln in die neue Datenbank kopiert.


Alternativ möchten Sie möglicherweise keine Benutzerentitäten vom alten auf das neue System kopieren.


In diesem Fall finden Sie hier einen Link zu einem Artikel, in dem beschrieben wird, wie Sie das Standardbenutzermodell in Django (das oben beschriebene JoomlaUser-Modell) durch Ihr eigenes ersetzen .


Die endgültige Entscheidung, ob Benutzer übertragen werden sollen oder nicht, wird auf der Grundlage der Beziehung getroffen, in der sich das neue und das alte Projekt befinden. Wo findet beispielsweise die Registrierung neuer Benutzer statt, welche Site / Anwendung wird die Hauptwebsite sein usw.


Test und Dokumentation


Fügen Sie nun die entsprechenden Tests und Dokumentationen hinzu, die den neuen Code abdecken. Die Logik dieser Lösung ist eng mit der Django-Architektur verknüpft und nicht sehr offensichtlich. Wenn Sie die Tests / Dokumentationen jetzt nicht durchführen, wird die Unterstützung für das Projekt in Zukunft komplizierter.

Source: https://habr.com/ru/post/de442592/


All Articles