Menggunakan Akun Joomla dalam Proyek Django

Katakanlah bahwa situs yang digunakan pengguna Anda ditulis dalam Joomla, tetapi untuk membuat produk baru untuk audiens Anda, Anda memilih bundel Python / Django.


Akibatnya, Anda perlu menggunakan akun pengguna dari database Joomla di Django.


Masalahnya, bagaimanapun, adalah bahwa Joomla dan Django menggunakan algoritma hashing kata sandi yang berbeda, jadi hanya menyalin akun gagal.


Setelah membaca dokumentasi Django, stack overflow dan menghabiskan waktu, saya mendapatkan solusi yang dijelaskan di bawah ini, yang menggunakan praktik pengembangan yang disarankan untuk Django secara maksimal.


Peringatan


Solusi arsitektur ini mungkin tidak cocok untuk Anda, lihat diskusi di komentar .


Untuk memahami apa yang terjadi dalam contoh di bawah ini, Anda harus memiliki pemahaman tentang arsitektur Django.


Saya juga berasumsi bahwa Anda tahu cara menggunakan proyek Django, jadi saya tidak menjelaskan proses ini.


Kode disalin dari proyek yang berfungsi, tetapi akan mudah untuk menyesuaikan dengan proyek Anda dengan minimum perubahan.


Mungkin, dalam versi utama Django berikutnya, kode ini dapat rusak, namun, prinsip solusinya akan tetap sama.


Dalam panduan ini, saya tidak menjelaskan ujung depan sistem otorisasi, karena:


  • apa front-end yang Anda miliki akan tergantung pada kebutuhan proyek Anda (bahkan mungkin titik akhir Json API, misalnya)
  • informasi ini sudah dijelaskan dalam tutorial resmi Django dan berbagai artikel pemula

Algoritma


  • sambungkan database Joomla (DB) ke proyek Django
  • buat model JoomlaUser yang mewakili pengguna dari database Joomla
  • tulis fungsi check_joomla_password() yang memverifikasi bahwa kata sandi yang dimasukkan cocok dengan kata sandi asli pengguna.
  • tambahkan backend otorisasi baru "Joomla Auth Backend" ke proyek, yang, ketika mengotorisasi klien di Django, akan mendapatkan akun pengguna dari database Joomla

1. Koneksi ke database Joomla:


  • Baca bagaimana Django bekerja dengan banyak basis data
  • Untuk menghubungkan database Joomla ke proyek Django kami, tambahkan kode berikut ke file pengaturan proyek /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', } } 


Jika perlu, dalam file yang sama dengan pengaturan proyek, Anda dapat mengaktifkan pencatatan permintaan basis data:


 # 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. buat model JoomlaUser


  • Baca bagaimana model Django dapat menggunakan database yang ada
  • Pikirkan tentang di mana menempatkan JoomlaUser baru.
    Dalam proyek saya, saya membuat aplikasi yang disebut "pengguna" ( manage.py startapp users ). Ini akan berisi backend otorisasi dan model pengguna Joomla.
  • buat model secara otomatis menggunakan inspectdb:
    python manage.py inspectdb live_users --database="joomla_db"
    joomla_db - nama database yang Anda tentukan di settings.py/DATABASES ;
    live_users - nama tabel dengan akun.
  • tambahkan model Anda ke 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" 


Selanjutnya, kita perlu memastikan bahwa model akan mengakses database yang benar. Untuk melakukan ini, tambahkan proyek router untuk permintaan ke database yang berbeda , yang akan mengarahkan permintaan dari model JoomlaUser ke database asli.


  1. Buat file "db_routers.py" di folder utama proyek (di tempat yang sama dengan "settings.py" Anda):


     # 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. daftarkan router baru di settings.py :


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


Sekarang Anda bisa mendapatkan akun dari basis data lama.
Luncurkan terminal Django dan coba tarik pengguna yang sudah ada: python manage.py shell


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

Jika semuanya berfungsi (Anda melihat pengguna), maka lanjutkan ke langkah berikutnya. Jika tidak, lihat output kesalahan dan koreksi pengaturan.


3. Verifikasi Kata Sandi Akun Joomla


Joomla tidak menyimpan kata sandi pengguna, tetapi hash mereka, misalnya
$2y$10$aoZ4/bA7pe.QvjTU0R5.IeFGYrGag/THGvgKpoTk6bTz6XNkY0F2e


Dimulai dengan Joomla v3.2, kata sandi pengguna dienkripsi menggunakan algoritma BLOWFISH .


Jadi saya mengunduh kode python dengan algoritma ini:


 pip install bcrypt echo bcrypt >> requirements.txt 

Dan membuat fungsi untuk memeriksa kata sandi di file 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) 

Perhatian! Versi Joomla lebih rendah dari 3,2 menggunakan metode hashing yang berbeda (md5 + garam), jadi fungsi ini tidak akan berfungsi. Dalam hal ini, baca
diskusi tentang Stackoverflow dan buat fungsi pemeriksaan hash yang terlihat seperti ini:


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

Sayangnya, saya tidak memiliki basis pengguna dari versi lama Joomla, jadi saya tidak dapat menguji fitur ini untuk Anda.


4. Backend otorisasi pengguna Joomla


Sekarang Anda siap membuat backend Django untuk mengesahkan pengguna dari proyek Joomla.


  1. baca cara memodifikasi sistem otorisasi Django


  2. Daftarkan backend baru (belum ada) di 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. Buat backend otorisasi pengguna Joomla di 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 

Ringkasan


Selamat - sekarang pengguna situs Joomla Anda yang ada dapat menggunakan kredensial mereka di situs / aplikasi baru.


Sebagai otorisasi pengguna aktif melalui antarmuka baru, mereka akan disalin satu per satu ke dalam basis data baru.


Atau, Anda mungkin tidak ingin menyalin entitas pengguna dari sistem lama ke yang baru.


Dalam hal ini, inilah tautan ke artikel yang menjelaskan cara mengganti model pengguna default dengan Anda sendiri di Django (model JoomlaUser dijelaskan di atas).


Keputusan akhir, apakah atau tidak untuk mentransfer pengguna, dibuat berdasarkan hubungan di mana proyek-proyek baru dan lama akan. Misalnya, di mana pendaftaran pengguna baru berlangsung, situs / aplikasi mana yang akan menjadi yang utama, dll.


Pengujian dan dokumentasi


Sekarang tolong tambahkan tes dan dokumentasi yang sesuai yang mencakup kode baru. Logika solusi ini terkait erat dengan arsitektur Django dan tidak terlalu jelas, jadi jika Anda tidak melakukan tes / dokumentasi sekarang, dukungan untuk proyek akan menjadi lebih rumit di masa depan.

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


All Articles