将用户帐户从 Joomla 迁移到 Django

发布于 2024-08-16 12:05:00 字数 81 浏览 3 评论 0原文

我正在对最初使用 Joomla 制作的网站进行大修,我想知道是否可以直接从 Joomla 导入用户记录(我主要关心的是用户密码,因为它们是加密的)。

I'm overhauling a site I'd originally made using Joomla to Django, and I was wondering if I can import the user records directly from Joomla (my main concern is the user passwords as they are encrypted).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

东走西顾 2024-08-23 12:05:01

是的,你可以,但你必须做一些工作。 Joomla 将用户保留在某些特定的数据库表结构中,因此您必须将它们取出并将它们插入到您在 Django 应用程序中创建的用户表中。至于加密,如果算法已知,它可能是保存在数据库中的哈希值,只要您在 Django 应用程序中实现相同的哈希算法,您就可以按原样传输它。

请记住:Django 是一个比 Joomla 更通用的“概念”——它是一个用于编写 Web 应用程序的框架,因此理论上您甚至可以用它完全重新实现 Joomla。

Yes, you can, but you'll have to do some work. Joomla keeps users in some specific DB table structure, so you'll have to pull them out and insert them into a users table you create in your Django application. As for encryption, if the algorithm is known, it's probably the hash value that's kept in the DB, and you can just transfer it as-is as long as you implement the same hashing algorithm in your Django application.

Remember: Django is a more general 'concept' than Joomla - it's a framework for writing web application, hence in theory you can even re-implement Joomla completely with it.

薄凉少年不暖心 2024-08-23 12:05:01

Django 中的 Joomla 用户(Django 身份验证后端,从 Joomla 填充用户)

一旦我需要在用 Django 编写的新 API 中使用现有的 Joomla 用户。
问题是我无法将 Joomla 用户复制到 Django 数据库中,因为:

  • Joomla 密码哈希系统与 Django 不同。
  • J 用户和 D 用户有不同的字段集(这很容易修复,但仍然)

所以我为 Django 制作了一个自定义身份验证后端,现在我可以自信地说

Django 可以根据 Joomla 对用户进行身份验证 实现

算法:

  • 将 Joomla 数据库连接到 Django 项目
  • 创建 JoomlaUser 模型,从 Joomla DB 填充用户
  • check_joomla_password( ) 函数,以与 Joomla 相同的方式验证用户密码
  • 添加自定义“Joomla Auth Backend”,在第一次登录时将每个用户从 Joomla 复制到 Django

实现:

要了解发生了什么,您应该有一些使用 Django 的经验。
代码必须根据您的 django 项目进行相应修改。
然而,代码是从工作项目中获取的,并且进行了最小的更改,
并且应该很容易根据您的需求进行设置。

1. 连接到 Joomla DB:

DATABASES = {
    'default': {"your default DB settings"},

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

# 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. 创建 Joomla 用户模型

  • 读取 https://docs.djangoproject.com/en/2.1/howto/legacy-databases/
  • 思考在哪里保存新的“Joomla 用户”模型。
    在我的项目中,我创建了 'users' 应用程序,其中包含我的自定义用户模型,
    并且将放置自定义 Joomla 后端。
  • 检查用户如何存储在现有的 Joomla DB 中:
    python manage.pyspectdb --database="joomla_db"
  • 查找并仔细检查 users 表。
  • 添加到 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"  

为了确保 JoomlaUser 模型将使用正确的数据库,请添加 数据库路由器

  1. 在项目文件夹中创建文件“db_routers.py”,其中存储“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_users':
            return 'joomla_db'
        return None

    def db_for_write(self, model, **kwargs):
        if model._meta.app_label == 'joomla_users':
            return 'joomla_db'
        return None
  1. 注册新路由器,为此,添加 settings.py
# ensure that Joomla users are populated from the right database:
DATABASE_ROUTERS = ['project_name.db_routers.DbRouter']

现在转到 django shell ./manage.py shell 并尝试填充一些用户,例如,

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

如果一切正常 - 移动继续下一步。否则检查错误、修复设置等

3. 检查 Joomla 用户密码

Joomla 不存储用户密码,而是存储密码哈希,例如
$2y$10$aoZ4/bA7pe.QvjTU0R5.IeFGYrGag/THGvgKpoTk6bTz6XNkY0F2e

从 Joomla v3.2 开始,用户密码使用 BLOWFISH 算法。

所以我下载了一个Python的Blowfish实现:

pip install bcrypt
echo bcrypt >> requirements.txt

并在users/backend.py中创建了Joomla密码检查功能:

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 from Joomla.

    :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)

旧版本警告! Joomla < 3.2 使用不同的哈希方法(md5+salt),
所以这个功能不会工作。
在这种情况下,请阅读joomla密码加密
并在 python 中实现一个哈希检查器,它可能看起来像这样:

# WARNING - THIS FUNCTION 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 身份验证后端

现在您已准备好为 Django 创建 Joomla 身份验证后端。

  1. 阅读如何修改 django auth 后端:https://docs. djangoproject.com/en/dev/topics/auth/customizing/

  2. 在 中注册 Jango(尚不存在)后端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',
]
  1. users/中创建Joomla身份验证后端backend.py
from django.contrib.auth.models import User
from .models import JoomlaUser

""" check password function we wrote before """
def check_joomla_password(password, hashed):
    ...


class JoomlaBackend:
    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 identical Django user:
            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 站点的客户可以在新 Django 站点或 REST API 等上使用他们的凭据。

现在,添加适当的测试和文档来涵盖此新代码。
它的逻辑非常棘手,所以如果你不进行测试和文档(懒惰的家伙) - 维护该项目将是你(或其他人)的痛苦。

亲切的问候,
@ Dmytro Gierman

更新 11.04.2019 - 错误已修复。

Joomla users in Django (Django auth backend, that populates users from Joomla)

Once I was in need to use our existing Joomla users in my new API, written in Django.
Problem is that I could not just copy Joomla users into a Django database, because:

  • Joomla password hashing system differs from Django one.
  • J-users and D-users had different set of fields (this is easy to fix, but still)

So instead I made a custom auth backend for Django, and now I can confidently say that

Django can authenticate users against the Joomla database, without need to decrypt password hashes or to copy all users from Joomla DB at once.

Algorithm:

  • connect the Joomla database to the Django project
  • create JoomlaUser model, to populate users from the Joomla DB
  • implement check_joomla_password() function, that validates user passwords the same way as Joomla
  • add custom "Joomla Auth Backend" that copies each user from Joomla to Django at the first login

Implementation:

To understand what's going on, you should have some experience with Django.
The code have to be modified accordingly to your django project.
However the code is taken from the working project with minimum changes,
and it should be easy to set up for your needs.

1. connect to Joomla DB:

DATABASES = {
    'default': {"your default DB settings"},

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

# 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. create Joomla user model

  • Read https://docs.djangoproject.com/en/2.1/howto/legacy-databases/
  • Think where to keep new "Joomla user" model.
    In my project I've created 'users' app, where my custom user models live,
    and the custom Joomla backend will be placed.
  • inspect how the user is stored in the existing Joomla DB:
    python manage.py inspectdb --database="joomla_db"
  • Find and carefully examine the users table.
  • Add to 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"  

To ensure, that JoomlaUser model will use right DB, add a database router:

  1. Create file "db_routers.py" in the project folder, where the "settings.py" file is stored:
# 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_users':
            return 'joomla_db'
        return None

    def db_for_write(self, model, **kwargs):
        if model._meta.app_label == 'joomla_users':
            return 'joomla_db'
        return None
  1. register new router, for that, add in settings.py:
# ensure that Joomla users are populated from the right database:
DATABASE_ROUTERS = ['project_name.db_routers.DbRouter']

Now go to django shell ./manage.py shell and try to populate some users, e.g.

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

If everything works - move on to the next step. Otherwise look into errors, fix settings, etc

3. Check Joomla user passwords

Joomla does not store user password, but the password hash, e.g.
$2y$10$aoZ4/bA7pe.QvjTU0R5.IeFGYrGag/THGvgKpoTk6bTz6XNkY0F2e

Starting from Joomla v3.2, user passwords are hashed using BLOWFISH algorithm.

So I've downloaded a python blowfish implementation:

pip install bcrypt
echo bcrypt >> requirements.txt

And created Joomla password check function in the 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 from Joomla.

    :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)

Old versions Warning! Joomla < 3.2 uses different hashing method (md5+salt),
so this function won't work.
In this case read joomla password encryption
and implement a hash checker in python, which probably will look something like:

# WARNING - THIS FUNCTION 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()

Unfortunately I have no old Joomla instance running, thus I couldn't test this function for you.

4. Joomla Authentication Backend

Now you are ready to create a Joomla authentication backend for Django.

  1. read how to modify django auth backends: https://docs.djangoproject.com/en/dev/topics/auth/customizing/

  2. Register Jango (not yet existing) backend in the 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',
]
  1. Create Joomla authentication Backend in users/backend.py:
from django.contrib.auth.models import User
from .models import JoomlaUser

""" check password function we wrote before """
def check_joomla_password(password, hashed):
    ...


class JoomlaBackend:
    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 identical Django user:
            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

Test & documentation

Congratulations - now your customers from old Joomla site can use their credentials on the new Django site or rest api, etc

Now, add proper tests and documentation to cover this new code.
It's logic is quite tricky, so if you won't make tests&docs (lazy dude) - maintaining the project will be a pain in your (or somebody's else) ass.

Kind regards,
@ Dmytro Gierman

Update 11.04.2019 - errors fixed.

墟烟 2024-08-23 12:05:01

我认为有 3 种方法可以解决这个问题:

1)您可以阅读 joomla 和 django 如何制作密码散列并使用脚本进行迁移
2)您可以制作自己的身份验证后端
3)您可以使用
ETL工具

I think there is 3 ways to approach this problem:

1) You can read about how joomla and django make hash of passwords and make the migration with a script
2) You can make your own authentication backend
3) You can use a ETL tool

谁对谁错谁最难过 2024-08-23 12:05:01

Joomla (PHP) 是一个 CMS,而 Django (Python) 是一个 Web 框架。

我想知道这是否真的可能。我现在可以得出的结论是这是不可能的。然而,有人可能对此有任何想法。

谢谢 :)

Joomla (PHP) is a CMS while Django (Python) is a web framework.

I wonder whether this is really possible. What i can conclude at this point of time is that it is not possible. However someone may have any idea about this.

Thanks :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文