Utilisation de comptes Joomla dans un projet Django

Disons que le site que vos utilisateurs utilisent est écrit en Joomla, mais pour créer un nouveau produit pour votre public, vous avez choisi le bundle Python / Django.


Par conséquent, vous devez utiliser des comptes d'utilisateurs de la base de données Joomla dans Django.


Le problème, cependant, est que Joomla et Django utilisent des algorithmes de hachage de mot de passe différents, donc la copie des comptes échoue.


Après avoir lu la documentation de Django, débordement de pile et avoir passé un certain temps, j'ai obtenu la solution décrite ci-dessous, qui utilise au maximum les pratiques de développement recommandées pour Django.


Avertissements


Cette solution architecturale peut ne pas vous convenir, voir la discussion dans les commentaires .


Pour comprendre ce qui se passe dans les exemples ci-dessous, vous devez avoir une certaine compréhension de l'architecture Django.


Je suppose également que vous savez comment déployer un projet Django, donc je ne décris pas ce processus.


Le code est copié à partir d'un projet fonctionnel, mais il sera facile de s'adapter à votre projet avec un minimum de modifications.


Probablement, dans la prochaine version majeure de Django, ce code risque de casser, cependant, le principe de la solution restera le même.


Dans ce guide, je ne décris pas l'extrémité avant du système d'autorisation, car:


  • le front-end dont vous disposez dépendra des besoins de votre projet (il peut même s'agir d'un point de terminaison de l'API Json, par exemple)
  • ces informations sont déjà décrites dans les tutoriels officiels de Django et divers articles de démarrage

Algorithme


  • connecter la base de données Joomla (DB) au projet Django
  • créer un modèle JoomlaUser représentant un utilisateur de la base de données Joomla
  • écrire une fonction check_joomla_password() qui vérifie que le mot de passe entré correspond au mot de passe d'origine de l'utilisateur.
  • ajouter un nouveau backend d'autorisation "Joomla Auth Backend" au projet qui, lors de l'autorisation du client dans Django, obtiendra le compte utilisateur de la base de données Joomla

1. Connexion à la base de données Joomla:


  • Découvrez comment Django fonctionne avec plusieurs bases de données
  • Pour connecter la base de données Joomla à notre projet Django, ajoutez le code suivant au fichier de paramètres du projet /project_name/settings.py :


     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', } } 


Si nécessaire, dans le même fichier avec les paramètres du projet, vous pouvez activer la journalisation des requêtes de base de données:


 # 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. créer un modèle JoomlaUser


  • Découvrez comment un modèle Django peut utiliser une base de données existante
  • Réfléchissez à l'emplacement du nouveau JoomlaUser.
    Dans mon projet, j'ai créé une application appelée "utilisateurs" ( manage.py startapp users ). Il contiendra le backend d'autorisation et le modèle utilisateur Joomla.
  • générer le modèle automatiquement en utilisant inspectdb:
    python manage.py inspectdb live_users --database="joomla_db"
    joomla_db - le nom de la base de données que vous avez spécifiée dans settings.py/DATABASES ;
    live_users - nom de la table avec les comptes.
  • ajoutez votre modèle à 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" 


Ensuite, nous devons nous assurer que le modèle accédera à la bonne base de données. Pour ce faire, ajoutez au projet un routeur pour les requêtes vers différentes bases de données , qui redirigera les requêtes du modèle JoomlaUser vers sa base de données native.


  1. Créez le fichier "db_routers.py" dans le dossier principal du projet (au même endroit où se trouve votre "settings.py"):


     # 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. enregistrer un nouveau routeur dans settings.py :


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


Vous pouvez maintenant obtenir un compte dans l'ancienne base de données.
Lancez un terminal Django et essayez d'extraire un utilisateur existant: python manage.py shell


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

Si tout fonctionne (vous voyez l'utilisateur), passez à l'étape suivante. Sinon, regardez la sortie d'erreur et corrigez les paramètres.


3. Vérifiez le mot de passe du compte Joomla


Joomla ne stocke pas les mots de passe des utilisateurs, mais leur hachage, par exemple
$2y$10$aoZ4/bA7pe.QvjTU0R5.IeFGYrGag/THGvgKpoTk6bTz6XNkY0F2e


À partir de Joomla v3.2, les mots de passe des utilisateurs sont cryptés à l'aide de l'algorithme BLOWFISH .


J'ai donc téléchargé du code python avec cet algorithme:


 pip install bcrypt echo bcrypt >> requirements.txt 

Et créé une fonction pour vérifier les mots de passe dans le 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) 

Attention! Les versions de Joomla inférieures à 3.2 utilisent une méthode de hachage différente (md5 + sel), donc cette fonction ne fonctionnera pas. Dans ce cas, lisez
discussion sur Stackoverflow et créer une fonction de vérification de hachage qui ressemble à ceci:


 # 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() 

Malheureusement, je n'ai pas de base d'utilisateurs de l'ancienne version de Joomla à portée de main, donc je ne peux pas tester cette fonctionnalité pour vous.


4. Autorisation utilisateur backend Joomla


Vous êtes maintenant prêt à créer un backend Django pour autoriser les utilisateurs du projet Joomla.


  1. lire comment modifier le système d'autorisation Django


  2. Enregistrez un nouveau backend (pas encore existant) dans 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. Créez un backend d'autorisation utilisateur Joomla dans 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 

Résumé


Félicitations - les utilisateurs de votre site Joomla existant peuvent désormais utiliser leurs informations d'identification sur un nouveau site / application.


En tant qu'autorisation des utilisateurs actifs via la nouvelle interface, ils seront copiés un par un dans la nouvelle base de données.


Vous pouvez également ne pas vouloir copier les entités utilisateur de l'ancien système vers le nouveau.


Dans ce cas, voici un lien vers un article qui décrit comment remplacer le modèle utilisateur par défaut dans Django par le vôtre (le modèle JoomlaUser décrit ci-dessus).


La décision finale, de transférer ou non les utilisateurs, est prise sur la base de la relation dans laquelle les nouveaux et anciens projets seront. Par exemple, où aura lieu l'enregistrement des nouveaux utilisateurs, quel site / application sera le principal, etc.


Test et documentation


Veuillez maintenant ajouter les tests et la documentation appropriés couvrant le nouveau code. La logique de cette solution est étroitement liée à l'architecture Django et n'est pas très évidente, donc si vous ne faites pas les tests / la documentation maintenant, le support du projet deviendra plus difficile à l'avenir.

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


All Articles