4

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

4

4 回答 4

3

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

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

于 2010-01-02T07:10:09.550 回答
2

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

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

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

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

Django 可以针对 Joomla 数据库对用户进行身份验证,而无需解密密码哈希或一次从 Joomla DB 复制所有用户。

算法:

  • 将 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.py inspectdb --database="joomla_db"
  • 查找并仔细检查用户表。
  • 添加到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 河豚实现:

pip install bcrypt
echo bcrypt >> requirements.txt

并在以下位置创建了 Joomla 密码检查功能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)

旧版本警告!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. 在以下位置创建 Joomla 身份验证后端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

测试和文档

恭喜 - 现在您来自旧 Joomla 站点的客户可以在新的 Django 站点或 rest api 等上使用他们的凭据

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

亲切的问候,@ Dmytro Gierman

更新 11.04.2019 - 修复了错误。

于 2019-01-30T13:16:27.970 回答
1

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

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

于 2010-01-02T07:42:20.383 回答
0

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

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

谢谢 :)

于 2010-01-02T07:00:15.477 回答