2

我正在使用 Moodle 的外部数据库插件并且遇到了一个非常烦人的问题。这是一个例子:

用户名: johndoe@gmail.com 使用他的密码登录,两者都保存在外部数据库中。Moodle 获取该数据(用户名、密码)并使用该用户的外部数据库 ID 将其保存在本地(mysql)。请记住,外部数据库是一切发生的主要数据库,Moodle 仅适用于需要进行测试的授权用户。所以在 Moodle 中,我有:

用户名:johndoe@gmail.com 密码:blabla 用户名:1​​234

它工作得很好,除了johndoe@gmail.com 决定在外部数据库上更新他的用户名/电子邮件,所以他现在希望它是 johndoe@hotmail.com。当他尝试登录时,它可以正常登录,因为 Moodle 会使用外部数据库检查用户名/密码。问题:在 Moodle 中为 johndoe@hotmail.com 创建了一条新记录,密码用户名相同。

我的问题是:如果用户 ID 已经存在并且创建新记录,我在哪里可以安全地检查本地数据库?我不想更新 moodlelib 文档,因为我不想在将来遇到升级问题。我可以更新外部数据库插件,但不知道哪里最好。

这是有人做过的解决方法-https: //moodle.org/mod/forum/discuss.php?d=232163-但它是在cron作业中完成的,而不是在登录时立即完成。

更新: 看起来我必须更新moodlelib和外部数据库插件,如果没有人发帖,我会发布我的解决方案。

4

2 回答 2

1

由于没有人回复,这是我能想到的最好的。我对 *UPDATED 有自己的评论,所以你知道我在哪里更新了代码。

\moodle\lib\moodlelib.php 下 (不幸的是,由于身份验证调用会触发重复创建,我不得不更新此文件)

1) 更新函数 authenticate_user_login();将第 4342 - 4382 行替换为:

$authsenabled = get_enabled_auth_plugins();

// *UPDATED - begin
$authplugin = get_auth_plugin('DB');
$userinfo = ($authplugin->get_userinfo($username)) ? $authplugin->get_userinfo($username) : 0;
// *UPDATED - end    

// *UPDATED - added second elseif
if ($user = get_complete_user_data('username', $username, $CFG->mnet_localhost_id)) {    
    // Use manual if auth not set.
    $auth = empty($user->auth) ? 'manual' : $user->auth;
    if (!empty($user->suspended)) {
        add_to_log(SITEID, 'login', 'error', 'index.php', $username);
        error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Suspended Login:  $username  ".$_SERVER['HTTP_USER_AGENT']);
        $failurereason = AUTH_LOGIN_SUSPENDED;
        return false;
    }
    if ($auth=='nologin' or !is_enabled_auth($auth)) {
        add_to_log(SITEID, 'login', 'error', 'index.php', $username);
        error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Disabled Login:  $username  ".$_SERVER['HTTP_USER_AGENT']);
        // Legacy way to suspend user.
        $failurereason = AUTH_LOGIN_SUSPENDED;
        return false;
    }
    $auths = array($auth);

} 
elseif ($user = get_complete_user_data('idnumber', $userinfo['idnumber'], $CFG->mnet_localhost_id)) {
    $auth = empty($user->auth) ? 'manual' : $user->auth;  // use manual if auth not set
    if (!empty($user->suspended)) {
        add_to_log(SITEID, 'login', 'error', 'index.php', $username);
        error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Suspended Login:  $username  ".$_SERVER['HTTP_USER_AGENT']);
        $failurereason = AUTH_LOGIN_SUSPENDED;
        return false;
    }
    if ($auth=='nologin' or !is_enabled_auth($auth)) {
        add_to_log(SITEID, 'login', 'error', 'index.php', $username);
        error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Disabled Login:  $username  ".$_SERVER['HTTP_USER_AGENT']);
        $failurereason = AUTH_LOGIN_SUSPENDED; // Legacy way to suspend user.
        return false;
    }
    $auths = array($auth);    
}    
else {
    // Check if there's a deleted record (cheaply), this should not happen because we mangle usernames in delete_user().
    if ($DB->get_field('user', 'id', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id,  'deleted' => 1))) {
        error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Deleted Login:  $username  ".$_SERVER['HTTP_USER_AGENT']);
        $failurereason = AUTH_LOGIN_NOUSER;
        return false;
    }

    // Do not try to authenticate non-existent accounts when user creation is not disabled.
    if (!empty($CFG->authpreventaccountcreation)) {
        add_to_log(SITEID, 'login', 'error', 'index.php', $username);
        error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Unknown user, can not create new accounts:  $username  ".$_SERVER['HTTP_USER_AGENT']);
        $failurereason = AUTH_LOGIN_NOUSER;
        return false;
    }

    // User does not exist.
    $auths = $authsenabled;
    $user = new stdClass();
    $user->id = 0;
}

2) 相同的功能,将第 4408 - 4427 行替换为:

if ($user->id) {
    // User already exists in database.
    if (empty($user->auth)) {
        // For some reason auth isn't set yet.
        // *UPDATED $DB->set_field('user', 'auth', $auth, array('username'=>$username));
        $DB->set_field('user', 'auth', $auth, array('idnumber'=>$user->idnumber));                
        $user->auth = $auth;
    }

    // If the existing hash is using an out-of-date algorithm (or the legacy md5 algorithm), then we should update to
    // the current hash algorithm while we have access to the user's password.
    update_internal_user_password($user, $password);

    if ($authplugin->is_synchronised_with_external()) {
        // Update user record from external DB.
        // *UPDATED $user = update_user_record($username);
        $user = $authplugin->update_user_record($username, $user->idnumber);                
    }
} else {
    // Create account, we verified above that user creation is allowed.
    $user = create_user_record($username, $password, $auth);
}

\moodle\auth\db\auth.php 下 (外部数据库插件库)

1) 更新函数 update_user_record() 以接收 IDNUMBER 参数:

function update_user_record($username, $idnumber='', $updatekeys=false) {  

2) 将第 512 行替换为:

$user = $DB->get_record('user', array('idnumber'=>$idnumber, 'mnethostid'=>$CFG->mnet_localhost_id)); 

所以现在,moodle lib下的主要功能将通过用户名检查用户是否存在,如果不存在,则检查用户ID是否存在......如果存在,它将使用来自外部数据库的新信息更新用户信息。对我来说,它在 Moodle 2.4 和 2.6 上运行良好。

于 2013-11-22T21:51:56.280 回答
1

这是一个相当古老的答案,但有一个不需要手动修补的替代方案。

OP 使用电子邮件地址(而不是任意用户名)来识别用户。authloginviaemail可以通过将站点管理 > 插件 > 身份验证 > 管理身份验证 > 允许通过电子邮件登录 ( ) 设置为 true来维护此行为。现在用户名可以由(稳定的)外部数据库 ID 填充。因此,更改电子邮件地址不会产生新帐户。

于 2021-04-10T16:00:48.260 回答