DjangoプロジェクトでのJoomlaアカウントの使用

ユーザーが使用するサイトがJoomlaで記述されているとしましょう。ただし、視聴者向けの新しい製品を作成するには、Python / Djangoバンドルを選択しました。


そのため、DjangoのJoomlaデータベースのユーザーアカウントを使用する必要があります。


ただし、問題は、JoomlaとDjangoが異なるパスワードハッシュアルゴリズムを使用するため、アカウントのコピーだけが失敗することです。


Djangoのドキュメントを読み、スタックオーバーフローを起こし、しばらく時間を費やした後、以下に説明するソリューションを得ました。これは、Djangoの推奨開発プラクティスを最大限に活用しています。


警告


このアーキテクチャ上の解決策はあなたに合わないかもしれません。 コメントの議論を参照してください。


以下の例で何が起こるかを理解するには、Djangoアーキテクチャについてある程度理解している必要があります。


また、Djangoプロジェクトをデプロイする方法を知っていると想定しているため、このプロセスについては説明しません。


コードは作業中のドラフトからコピーされますが、最小限の変更でプロジェクトに簡単に調整できます。


おそらく、Djangoの次のメジャーバージョンでは、このコードが破損する可能性がありますが、ソリューションの原則は変わりません。


このガイドでは、承認システムのフロントエンドについては説明しません。



アルゴリズム



1. Joomlaデータベースへの接続:



必要に応じて、プロジェクト設定と同じファイルで、データベースクエリのログを有効にできます。


 # 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. JoomlaUserモデルを作成する



次に、モデルが正しいデータベースにアクセスすることを確認する必要があります。 これを行うには、 異なるデータベースへのクエリ用のルーターをプロジェクトに追加します。これにより、リクエストがJoomlaUserモデルからネイティブデータベースにリダイレクトされます。


  1. プロジェクトのメインフォルダー( "settings.py"と同じ場所)にファイル "db_routers.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. settings.py新しいルーターを登録しsettings.py


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


これで、古いデータベースからアカウントを取得できます。
Djangoターミナルを起動し、既存のユーザーをpython manage.py shellみます: python manage.py shell


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

すべてが機能する場合(ユーザーが表示されます)、次の手順に進みます。 それ以外の場合は、エラー出力を見て設定を修正します。


3. Joomlaアカウントのパスワードを確認する


Joomlaはユーザーパスワードを保存しませんが、たとえば、ハッシュ
$2y$10$aoZ4/bA7pe.QvjTU0R5.IeFGYrGag/THGvgKpoTk6bTz6XNkY0F2e


Joomla v3.2以降、ユーザーパスワードはBLOWFISHアルゴリズムを使用して暗号化されます。


だから私はこのアルゴリズムでPythonコードをダウンロードしました:


 pip install bcrypt echo bcrypt >> requirements.txt 

そして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) 

注意! 3.2より前のJoomlaバージョンは異なるハッシュ方式(md5 + salt)を使用するため、この関数は機能しません。 この場合、読む
Stackoverflowに関する議論と、次のようなハッシュチェック関数の作成:


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

残念ながら、古いバージョンのJoomlaのユーザーベースは手元にないため、この機能をテストすることはできません。


4.バックエンドユーザー認証Joomla


これで、Joomlaプロジェクトからユーザーを承認するためのDjangoバックエンドを作成する準備が整いました。


  1. Django認証システムの変更方法を読む


  2. project/settings.py新しいバックエンド(まだ存在しない)を登録し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. users/backend.pyでJoomlaユーザー認証バックエンドを作成します



 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 

まとめ


おめでとうございます-既存のJoomlaサイトのユーザーは、新しいサイト/アプリケーションで資格情報を使用できるようになりました。


新しいインターフェイスを介したアクティブユーザーの承認として、ユーザーは1つずつ新しいデータベースにコピーされます。


または、ユーザーエンティティを古いシステムから新しいシステムにコピーしたくない場合があります。


この場合、 Djangoでデフォルトのユーザーモデルを独自のモデル(上記のJoomlaUserモデル) に置き換える方法を説明した記事へのリンクがあります


ユーザーを転送するかどうかの最終決定は、新しいプロジェクトと古いプロジェクトの関係に基づいて行われます。 たとえば、新しいユーザーの登録が行われる場所、メインのサイト/アプリケーションなど。


テストとドキュメント


次に、新しいコードを対象とした適切なテストとドキュメントを追加してください。 このソリューションのロジックはDjangoアーキテクチャと密接に関連しており、あまり明確ではないため、テスト/ドキュメントを今すぐ行わないと、プロジェクトのサポートは将来より複雑になります。



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


All Articles